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) if (!warn_on_pl_erase()) return false; return bookmark_play(global_temp_buffer, bm.resume_index, - bm.resume_offset, bm.resume_seed, global_filename); + bm.resume_time, bm.resume_offset, bm.resume_seed, global_filename); } 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) playlist_shuffle(current_tick, -1); } - playlist_start(0, 0); + playlist_start(0, 0, 0); return true; } @@ -498,7 +498,7 @@ int ft_enter(struct tree_context* c) start_index = 0; } - playlist_start(start_index, 0); + playlist_start(start_index, 0, 0); play = true; } break; @@ -705,6 +705,7 @@ int ft_enter(struct tree_context* c) global_status.resume_index = start_index; global_status.resume_crc32 = playlist_get_filename_crc32(NULL, start_index); + global_status.resume_elapsed = 0; global_status.resume_offset = 0; status_save(); 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, (((wps_data->last_albumart_height != aa->height) || (wps_data->last_albumart_width != aa->width))))) { - long offset = audio_current_track()->offset; + struct mp3entry *id3 = audio_current_track(); + unsigned long elapsed = id3->elapsed; + unsigned long offset = id3->offset; audio_stop(); if (!(status & AUDIO_STATUS_PAUSE)) - audio_play(offset); + audio_play(elapsed, offset); } } #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, if (playlist_resume() != -1) { playlist_start(global_status.resume_index, + global_status.resume_elapsed, global_status.resume_offset); } } 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 if (resume && playlist_resume() != -1) { playlist_start(global_status.resume_index, + global_status.resume_elapsed, global_status.resume_offset); } resume = false; @@ -657,6 +658,7 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame if (playlist_resume() != -1) { playlist_start(global_status.resume_index, + global_status.resume_elapsed, global_status.resume_offset); } 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 */ static long low_watermark_margin = 0; /* Extra time in seconds for watermark */ static long lowest_watermark_level; /* Debug value to observe the buffer usage */ + +struct audio_resume_info +{ + unsigned long elapsed; + unsigned long offset; +}; + #if CONFIG_CODEC == MAS3587F static char recording_filename[MAX_PATH]; /* argument to thread */ static char delayed_filename[MAX_PATH]; /* internal copy of above */ @@ -430,10 +437,9 @@ static void set_elapsed(struct mp3entry* id3) id3->elapsed = id3->offset / (id3->bitrate / 8); } -int audio_get_file_pos(void) +static int audio_get_file_pos_int(struct mp3entry *id3) { int pos = -1; - struct mp3entry *id3 = audio_current_track(); if (id3->vbr) { @@ -490,6 +496,12 @@ int audio_get_file_pos(void) return pos; } +int audio_get_file_pos(void) +{ + struct mp3entry *id3 = audio_current_track(); + return id3 ? audio_get_file_pos_int(id3) : 0; +} + unsigned long mpeg_get_last_header(void) { #ifdef SIMULATOR @@ -545,7 +557,13 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s } /* TODO: Do it without stopping playback, if possible */ bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY; - long offset = audio_current_track()->offset; + struct mp3entry *id3 = audio_current_track(); + unsigned long elapsed = 0, offset = 0; + if (id3) + { + elapsed = id3->elapsed; + offset = id3->offset; + } /* don't call audio_hard_stop() as it frees this handle */ if (thread_self() == audio_thread_id) { /* 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 } if (playing) { /* safe to call even from the audio thread (due to queue_post()) */ - audio_play(offset); + audio_play(elapsed, offset); } return BUFLIB_CB_OK; @@ -1274,7 +1292,7 @@ static void mpeg_thread(void) int unplayed_space_left; int amount_to_read; int t1, t2; - int start_offset; + unsigned long start_elapsed, start_offset; #if CONFIG_CODEC == MAS3587F int amount_to_save; int save_endpos = 0; @@ -1337,9 +1355,16 @@ static void mpeg_thread(void) break; } - start_offset = (int)ev.data; + start_elapsed = ((struct audio_resume_info *)ev.data)->elapsed; + start_offset = ((struct audio_resume_info *)ev.data)->offset; /* mid-song resume? */ + if (!start_offset && start_elapsed) { + struct mp3entry *id3 = &get_trackdata(0)->id3; + id3->elapsed = start_elapsed; + start_offset = audio_get_file_pos_int(id3); + } + if (start_offset) { struct mp3entry* id3 = &get_trackdata(0)->id3; lseek(mpeg_file, start_offset, SEEK_SET); @@ -1506,7 +1531,7 @@ static void mpeg_thread(void) id3->elapsed = newtime; - newpos = audio_get_file_pos(); + newpos = audio_get_file_pos_int(id3); if(newpos < 0) { id3->elapsed = oldtime; @@ -2765,7 +2790,7 @@ static void audio_reset_buffer(void) audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize); } -void audio_play(long offset) +void audio_play(unsigned long elapsed, unsigned long offset) { audio_reset_buffer(); #ifdef SIMULATOR @@ -2789,15 +2814,28 @@ void audio_play(long offset) real_mpeg_play(trackname); #endif playlist_next(steps); - taginfo.offset = offset; - set_elapsed(&taginfo); + if (!offset && elapsed) + { + /* has an elapsed time but no offset; elapsed may take + precedence in this case */ + taginfo.elapsed = elapsed; + taginfo.offset = audio_get_file_pos_int(&taginfo); + } + else + { + taginfo.offset = offset; + set_elapsed(&taginfo); + } is_playing = true; playing = true; break; } while(1); #else /* !SIMULATOR */ + static struct audio_resume_info resume; is_playing = true; - queue_post(&mpeg_queue, MPEG_PLAY, offset); + resume.elapsed = elapsed; + resume.offset = offset; + queue_post(&mpeg_queue, MPEG_PLAY, (intptr_t)&resume); #endif /* !SIMULATOR */ 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) inserted */ if (global_settings.playlist_shuffle) playlist_shuffle(current_tick, -1); - playlist_start(0,0); + playlist_start(0, 0, 0); onplay_result = ONPLAY_START_PLAY; } 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 }; static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */ +struct audio_resume_info +{ + unsigned long elapsed; + unsigned long offset; +}; + /* Peeking functions can yield and mess us up */ static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/ @@ -325,7 +331,8 @@ enum audio_start_playback_flags AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */ }; -static void audio_start_playback(size_t offset, unsigned int flags); +static void audio_start_playback(const struct audio_resume_info *resume_info, + unsigned int flags); static void audio_stop_playback(void); static void buffer_event_buffer_low_callback(void *data); 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 /* codec messages */ { Q_AUDIO_PLAY, Q_AUDIO_PLAY }, }; + + static struct audio_resume_info resume; + bool give_up = false; + /* filebuflen is, at this point, the buffering.c buffer size, * i.e. the audiobuf except voice, scratch mem, pcm, ... */ 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 /* TODO: Do it without stopping playback, if possible */ - long offset = audio_current_track()->offset; + struct mp3entry *id3 = audio_current_track(); + unsigned long elapsed = id3->elapsed; + unsigned long offset = id3->offset; /* resume if playing */ bool playing = (audio_status() == AUDIO_STATUS_PLAY); /* 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 * queue_post from the last call to get the correct offset. This also * lets us conviniently remove the queue event so Q_AUDIO_PLAY is only * processed once. */ - bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, filter_list); + bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, + filter_list); - if (playing && offset > 0) /* current id3->offset is king */ - ev.data = offset; + if (playing && ev.data != (intptr_t)&resume) + { + resume = *(struct audio_resume_info *)ev.data; + + /* current id3->elapsed/offset are king */ + if (elapsed > 0) + resume.elapsed = elapsed; + + if (offset > 0) + resume.offset = offset; + } /* don't call audio_hard_stop() as it frees this handle */ if (thread_self() == audio_thread_id) @@ -867,7 +890,7 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s if (playing || play_queued) { /* post, to make subsequent calls not break the resume position */ - audio_queue_post(Q_AUDIO_PLAY, ev.data); + audio_queue_post(Q_AUDIO_PLAY, (intptr_t)&resume); } return BUFLIB_CB_OK; @@ -1099,7 +1122,8 @@ static void audio_update_and_announce_next_track(const struct mp3entry *id3_next /* Bring the user current mp3entry up to date and set a new offset for the buffered metadata */ -static void playing_id3_sync(struct track_info *user_info, off_t offset) +static void playing_id3_sync(struct track_info *user_info, + unsigned long elapsed, unsigned long offset) { id3_mutex_lock(); @@ -1113,9 +1137,14 @@ static void playing_id3_sync(struct track_info *user_info, off_t offset) id3_write(PLAYING_ID3, id3); - if (offset < 0) + if (elapsed == (unsigned long)-1) { playing_id3->elapsed = e; + elapsed = 0; + } + + if (offset == (unsigned long)-1) + { playing_id3->offset = o; offset = 0; } @@ -1123,7 +1152,10 @@ static void playing_id3_sync(struct track_info *user_info, off_t offset) pcm_play_unlock(); if (id3) + { + id3->elapsed = elapsed; id3->offset = offset; + } id3_mutex_unlock(); } @@ -1299,19 +1331,16 @@ static bool audio_get_track_metadata(int offset, struct mp3entry *id3) return false; } -/* Get a resume rewind adjusted offset from the ID3 */ -static unsigned long resume_rewind_adjusted_offset(const struct mp3entry *id3) +/* Get resume rewind adjusted progress from the ID3 */ +static void resume_rewind_adjust_progress(const struct mp3entry *id3, + unsigned long *elapsed, + unsigned long *offset) { - unsigned long offset = id3->offset; - size_t resume_rewind = global_settings.resume_rewind * - id3->bitrate * (1000/8); - - if (offset < resume_rewind) - offset = 0; - else - offset -= resume_rewind; - - return offset; + unsigned int rewind = MAX(global_settings.resume_rewind, 0); + unsigned long d_e = rewind*1000; + *elapsed = id3->elapsed - MIN(id3->elapsed, d_e); + unsigned long d_o = rewind * id3->bitrate * (1000/8); + *offset = id3->offset - MIN(id3->offset, d_o); } /* 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) #ifdef HAVE_TAGCACHE bool autoresume_enable = global_settings.autoresume_enable; - if (autoresume_enable && !cur_id3->offset) + if (autoresume_enable && !(cur_id3->elapsed || cur_id3->offset)) { /* Resume all manually selected tracks */ bool resume = !auto_skip; @@ -1466,10 +1495,13 @@ static bool audio_start_codec(bool auto_skip) } if (!resume) + { + cur_id3->elapsed = 0; cur_id3->offset = 0; + } - logf("%s: Set offset for %s to %lX\n", __func__, - cur_id3->title, cur_id3->offset); + logf("%s: Set resume for %s to %lu %lX", __func__, + cur_id3->title, cur_id3->elapsed, cur_id3->offset); } #endif /* HAVE_TAGCACHE */ @@ -1481,7 +1513,8 @@ static bool audio_start_codec(bool auto_skip) and back again will cause accumulation of silent rewinds - that's not our job to track directly nor could it be in any reasonable way */ - cur_id3->offset = resume_rewind_adjusted_offset(cur_id3); + resume_rewind_adjust_progress(cur_id3, &cur_id3->elapsed, + &cur_id3->offset); /* Update the codec API with the metadata and track info */ id3_write(CODEC_ID3, cur_id3); @@ -1494,7 +1527,7 @@ static bool audio_start_codec(bool auto_skip) codec_go(); #ifdef HAVE_TAGCACHE - if (!autoresume_enable || cur_id3->offset) + if (!autoresume_enable || cur_id3->elapsed || cur_id3->offset) #endif { /* Send the "buffer" event now */ @@ -1923,7 +1956,9 @@ static int audio_finish_load_track(struct track_info *info) /** Finally, load the audio **/ size_t file_offset = 0; - track_id3->elapsed = 0; + + if (track_id3->elapsed > track_id3->length) + track_id3->elapsed = 0; if (track_id3->offset >= info->filesize) track_id3->offset = 0; @@ -1933,7 +1968,11 @@ static int audio_finish_load_track(struct track_info *info) /* Adjust for resume rewind so we know what to buffer - starting the codec calls it again, so we don't save it (and they shouldn't accumulate) */ - size_t offset = resume_rewind_adjusted_offset(track_id3); + unsigned long elapsed, offset; + resume_rewind_adjust_progress(track_id3, &elapsed, &offset); + + logf("%s: Set resume for %s to %lu %lX", __func__, + id3->title, elapsed, offset); enum data_type audiotype = rbcodec_format_is_atomic(track_id3->codectype) ? TYPE_ATOMIC_AUDIO : TYPE_PACKET_AUDIO; @@ -2168,7 +2207,7 @@ static void audio_on_finish_load_track(int id3_hid) change otherwise */ bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3)); - playing_id3_sync(info, -1); + playing_id3_sync(info, -1, -1); if (!was_valid) { @@ -2306,7 +2345,7 @@ static void audio_begin_track_change(enum pcm_track_change_type type, if (audio_start_codec(auto_skip)) { if (!auto_skip) - playing_id3_sync(info, -1); + playing_id3_sync(info, -1, -1); return; } @@ -2455,8 +2494,11 @@ static void audio_on_track_changed(void) /* Begin playback from an idle state, transition to a new playlist or invalidate the buffer and resume (if playing). (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */ -static void audio_start_playback(size_t offset, unsigned int flags) +static void audio_start_playback(const struct audio_resume_info *resume_info, + unsigned int flags) { + struct audio_resume_info resume = + *(resume_info ?: &(struct audio_resume_info){ 0, 0 } ); enum play_status old_status = play_status; if (flags & AUDIO_START_NEWBUF) @@ -2469,7 +2511,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) if (old_status != PLAY_STOPPED) { - logf("%s(%lu): skipping", __func__, (unsigned long)offset); + logf("%s(%lu, %lu): skipping", __func__, resume.elapsed, + resume.offset); halt_decoding_track(true); @@ -2481,7 +2524,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) /* Clear out some stuff to resume the current track where it left off */ pcmbuf_play_stop(); - offset = id3_get(PLAYING_ID3)->offset; + resume.elapsed = id3_get(PLAYING_ID3)->elapsed; + resume.offset = id3_get(PLAYING_ID3)->offset; track_list_clear(TRACK_LIST_CLEAR_ALL); } else @@ -2505,7 +2549,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) return; /* Must already be playing */ /* Cold playback start from a stopped state */ - logf("%s(%lu): starting", __func__, offset); + logf("%s(%lu, %lu): starting", __func__, resume.elapsed, + resume.offset); /* Set audio parameters */ #if INPUT_SRC_CAPS != 0 @@ -2555,7 +2600,7 @@ static void audio_start_playback(size_t offset, unsigned int flags) if (trackstat >= LOAD_TRACK_OK) { /* This is the currently playing track - get metadata, stat */ - playing_id3_sync(track_list_current(0), offset); + playing_id3_sync(track_list_current(0), resume.elapsed, resume.offset); if (valid_mp3entry(id3_get(PLAYING_ID3))) { @@ -2892,7 +2937,9 @@ static void audio_on_ff_rewind(long time) if (!haltres) { - /* If codec must be (re)started, reset the offset */ + /* If codec must be (re)started, reset the resume info so that + it doesn't execute resume procedures */ + ci_id3->elapsed = 0; ci_id3->offset = 0; } @@ -2970,7 +3017,7 @@ static void audio_on_audio_flush(void) not possible so a restart is required in order to continue the currently playing track without the now invalid future track playing */ - audio_start_playback(0, AUDIO_START_RESTART); + audio_start_playback(NULL, AUDIO_START_RESTART); break; default: /* Nothing else is a state */ @@ -3008,7 +3055,7 @@ void audio_playback_handler(struct queue_event *ev) /** Control messages **/ case Q_AUDIO_PLAY: LOGFQUEUE("playback < Q_AUDIO_PLAY"); - audio_start_playback(ev->data, 0); + audio_start_playback((struct audio_resume_info *)ev->data, 0); break; #ifdef HAVE_RECORDING @@ -3082,7 +3129,7 @@ void audio_playback_handler(struct queue_event *ev) case Q_AUDIO_REMAKE_AUDIO_BUFFER: /* buffer needs to be reinitialized */ LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); - audio_start_playback(0, AUDIO_START_RESTART | AUDIO_START_NEWBUF); + audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF); if (play_status == PLAY_STOPPED) return; /* just need to change buffer state */ break; @@ -3368,8 +3415,8 @@ struct mp3entry * audio_next_track(void) return id3; } -/* Start playback at the specified offset */ -void audio_play(long offset) +/* Start playback at the specified elapsed time or offset */ +void audio_play(unsigned long elapsed, unsigned long offset) { logf("audio_play"); @@ -3379,8 +3426,9 @@ void audio_play(long offset) talk_force_shutup(); #endif - LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset); - audio_queue_send(Q_AUDIO_PLAY, offset); + LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %lu %lX", elapsed, offset); + audio_queue_send(Q_AUDIO_PLAY, + (intptr_t)&(struct audio_resume_info){ elapsed, offset }); } /* Stop playback if playing */ @@ -3582,11 +3630,10 @@ void playback_release_aa_slot(int slot) } #endif /* HAVE_ALBUMART */ -/* Would normally calculate byte offset from an elapsed time but is not - used on SWCODEC */ +/* Return file byte offset */ int audio_get_file_pos(void) { - return 0; + return id3_get(PLAYING_ID3)->offset; } /* 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) #if (CONFIG_CODEC == SWCODEC) current_playlist.started = true; #else - playlist_start(index, 0); + playlist_start(index, 0, 0); #endif } @@ -2565,7 +2565,8 @@ unsigned int playlist_get_filename_crc32(struct playlist_info *playlist, } /* resume a playlist track with the given crc_32 of the track name. */ -void playlist_resume_track(int start_index, unsigned int crc, int offset) +void playlist_resume_track(int start_index, unsigned int crc, + unsigned long elapsed, unsigned long offset) { int i; unsigned int tmp_crc; @@ -2573,7 +2574,7 @@ void playlist_resume_track(int start_index, unsigned int crc, int offset) tmp_crc = playlist_get_filename_crc32(playlist, start_index); if (tmp_crc == crc) { - playlist_start(start_index, offset); + playlist_start(start_index, elapsed, offset); return; } @@ -2582,17 +2583,18 @@ void playlist_resume_track(int start_index, unsigned int crc, int offset) tmp_crc = playlist_get_filename_crc32(playlist, i); if (tmp_crc == crc) { - playlist_start(i, offset); + playlist_start(i, elapsed, offset); return; } } /* If we got here the file wasnt found, so start from the beginning */ - playlist_start(0,0); + playlist_start(0, 0, 0); } /* start playing current playlist at specified index/offset */ -void playlist_start(int start_index, int offset) +void playlist_start(int start_index, unsigned long elapsed, + unsigned long offset) { struct playlist_info* playlist = ¤t_playlist; @@ -2605,7 +2607,7 @@ void playlist_start(int start_index, int offset) playlist->started = true; sync_control(playlist, false); - audio_play(offset); + audio_play(elapsed, offset); } /* Returns false if 'steps' is out of bounds, else true */ @@ -2723,7 +2725,7 @@ int playlist_next(int steps) #if CONFIG_CODEC == SWCODEC playlist->started = true; #else - playlist_start(0, 0); + playlist_start(0, 0, 0); #endif playlist->index = 0; index = 0; @@ -2801,11 +2803,13 @@ int playlist_update_resume_info(const struct mp3entry* id3) if (id3) { if (global_status.resume_index != playlist->index || + global_status.resume_elapsed != id3->elapsed || global_status.resume_offset != id3->offset) { unsigned int crc = crc_32(id3->path, strlen(id3->path), -1); global_status.resume_index = playlist->index; global_status.resume_crc32 = crc; + global_status.resume_elapsed = id3->elapsed; global_status.resume_offset = id3->offset; status_save(); } @@ -2814,6 +2818,7 @@ int playlist_update_resume_info(const struct mp3entry* id3) { global_status.resume_index = -1; global_status.resume_crc32 = -1; + global_status.resume_elapsed = -1; global_status.resume_offset = -1; status_save(); } 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); int playlist_shuffle(int random_seed, int start_index); unsigned int playlist_get_filename_crc32(struct playlist_info *playlist, int index); -void playlist_resume_track(int start_index, unsigned int crc, int offset); -void playlist_start(int start_index, int offset); +void playlist_resume_track(int start_index, unsigned int crc, + unsigned long elapsed, unsigned long offset); +void playlist_start(int start_index, unsigned long elapsed, + unsigned long offset); bool playlist_check(int steps); const char *playlist_peek(int steps, char* buf, size_t buf_size); 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) { global_status.resume_index = -1; global_status.resume_offset = -1; + global_status.resume_elapsed = -1; return false; } playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD, @@ -466,6 +467,7 @@ static bool update_playlist(bool force) { global_status.resume_index = -1; global_status.resume_offset = -1; + global_status.resume_elapsed = -1; return false; } } @@ -526,7 +528,7 @@ static int onplay_menu(int index) if (current_track->display_index!=viewer.num_tracks || global_settings.repeat_mode == REPEAT_ALL) { - audio_play(0); + audio_play(0, 0); viewer.current_playing_track = -1; } } @@ -773,7 +775,7 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename) /* play new track */ if (!global_settings.party_mode) { - playlist_start(current_track->index, 0); + playlist_start(current_track->index, 0, 0); update_playlist(false); } } @@ -790,7 +792,7 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename) goto exit; if (global_settings.playlist_shuffle) start_index = playlist_shuffle(current_tick, start_index); - playlist_start(start_index, 0); + playlist_start(start_index, 0, 0); /* Our playlist is now the current list */ if (!playlist_viewer_init(&viewer, NULL, true)) @@ -937,7 +939,7 @@ bool search_playlist(void) case ACTION_STD_OK: { int sel = gui_synclist_get_sel_pos(&playlist_lists); - playlist_start(found_indicies[sel], 0); + playlist_start(found_indicies[sel], 0, 0); exit = 1; } 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); #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 226 +#define PLUGIN_API_VERSION 227 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any new function which are "waiting" at the end of the function table) */ -#define PLUGIN_MIN_API_VERSION 226 +#define PLUGIN_MIN_API_VERSION 227 /* plugin return codes */ /* internal returns start at 0x100 to make exit(1..255) work */ @@ -723,8 +723,10 @@ struct plugin_api { /* playback control */ int (*playlist_amount)(void); int (*playlist_resume)(void); - void (*playlist_resume_track)(int start_index, unsigned int crc, int offset); - void (*playlist_start)(int start_index, int offset); + void (*playlist_resume_track)(int start_index, unsigned int crc, + unsigned long elapsed, unsigned long offset); + void (*playlist_start)(int start_index, unsigned long elapsed, + unsigned long offset); int (*playlist_add)(const char *filename); void (*playlist_sync)(struct playlist_info* playlist); int (*playlist_remove_all_tracks)(struct playlist_info *playlist); @@ -735,7 +737,7 @@ struct plugin_api { const char *dirname, int position, bool queue, bool recurse); int (*playlist_shuffle)(int random_seed, int start_index); - void (*audio_play)(long offset); + void (*audio_play)(unsigned long elapsed, unsigned long offset); void (*audio_stop)(void); void (*audio_pause)(void); 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) if (rb->playlist_resume() != -1) { rb->playlist_resume_track(rb->global_status->resume_index, rb->global_status->resume_crc32, + rb->global_status->resume_elapsed, rb->global_status->resume_offset); } } 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) } else { - print_scroll("audio_play(0)"); - rb->audio_play(0); + print_scroll("audio_play(0, 0)"); + rb->audio_play(0, 0); } } 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) { rb->playlist_resume_track(rb->global_status->resume_index, rb->global_status->resume_crc32, + rb->global_status->resume_elapsed, rb->global_status->resume_offset); } } 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) { rb->playlist_resume_track(rb->global_status->resume_index, rb->global_status->resume_crc32, + rb->global_status->resume_elapsed, rb->global_status->resume_offset); } } 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: * if shuffle, we can't predict the playing track easily, and for either * case the track list doesn't get auto scrolled*/ if(!append) - rb->playlist_start(position, 0); + rb->playlist_start(position, 0, 0); old_playlist = center_slide.slide_index; old_shuffle = shuffle; } 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) } } rb->splash(HZ, "Done"); - rb->playlist_start(0,0); + rb->playlist_start(0, 0, 0); return 1; } 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) { playlist_resume_track(global_status.resume_index, global_status.resume_crc32, + global_status.resume_elapsed, global_status.resume_offset); ret_val = gui_wps_show(); } 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) bool changed = value != prev_setting; prev_setting = value; - long offset = 0; + unsigned long elapsed = 0; + unsigned long offset = 0; bool playing = changed && !playback && audio_status() == AUDIO_STATUS_PLAY; if (playing) - offset = audio_current_track()->offset; + { + struct mp3entry *id3 = audio_current_track(); + elapsed = id3->elapsed; + offset = id3->offset; + } if (changed && !playback) audio_hard_stop(); @@ -752,7 +757,7 @@ void settings_apply_play_freq(int value, bool playback) mixer_set_frequency(play_sampr[value]); if (playing) - audio_play(offset); + audio_play(elapsed, offset); } #endif /* HAVE_PLAY_FREQ */ 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 { int resume_index; /* index in playlist (-1 for no active resume) */ uint32_t resume_crc32; /* crc32 of the name of the file */ + uint32_t resume_elapsed; /* elapsed time in last file */ uint32_t resume_offset; /* byte offset in mp3 file */ int runtime; /* current runtime since last charge */ int topruntime; /* top known runtime */ @@ -282,6 +283,7 @@ struct system_status #ifdef HAVE_LCD_BITMAP int font_id[NB_SCREENS]; /* font id of the settings font for each screen */ #endif + }; 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[] = { OFFON_SETTING(0, playlist_shuffle, LANG_SHUFFLE, false, "shuffle", NULL), SYSTEM_SETTING(NVRAM(4), resume_index, -1), SYSTEM_SETTING(NVRAM(4), resume_crc32, -1), + SYSTEM_SETTING(NVRAM(4), resume_elapsed, -1), SYSTEM_SETTING(NVRAM(4), resume_offset, -1), CHOICE_SETTING(0, repeat_mode, LANG_REPEAT, REPEAT_OFF, "repeat", "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 { #define F_NVRAM_BYTES_MASK 0xE0000 /*0-4 bytes can be stored */ #define F_NVRAM_MASK_SHIFT 17 -#define NVRAM_CONFIG_VERSION 7 +#define NVRAM_CONFIG_VERSION 8 /* Above define should be bumped if - a new NVRAM setting is added between 2 other NVRAM settings - 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; static const char *tags_str[] = { "artist", "album", "genre", "title", "filename", "composer", "comment", "albumartist", "grouping", "year", "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating", - "playtime", "lastplayed", "commitid", "mtime", "lastoffset" }; + "playtime", "lastplayed", "commitid", "mtime", "lastelapsed", "lastoffset" }; /* Status information of the tagcache. */ static struct tagcache_stat tc_stat; @@ -196,7 +196,7 @@ static const char * const tagfile_entry_ec = "ll"; /** Note: This should be (1 + TAG_COUNT) amount of l's. */ -static const char * const index_entry_ec = "llllllllllllllllllllll"; +static const char * const index_entry_ec = "lllllllllllllllllllllll"; static const char * const tagcache_header_ec = "lll"; static const char * const master_header_ec = "llllll"; @@ -1752,6 +1752,10 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename) #if CONFIG_CODEC == SWCODEC if (global_settings.autoresume_enable) { + id3->elapsed = get_tag_numeric(entry, tag_lastelapsed, idx_id); + logf("tagcache_fill_tags: Set elapsed for %s to %lX\n", + id3->title, id3->elapsed); + id3->offset = get_tag_numeric(entry, tag_lastoffset, idx_id); logf("tagcache_fill_tags: Set offset for %s to %lX\n", id3->title, id3->offset); @@ -2348,6 +2352,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) tmpdb_copy_tag(tag_playtime); tmpdb_copy_tag(tag_lastplayed); tmpdb_copy_tag(tag_commitid); + tmpdb_copy_tag(tag_lastelapsed); tmpdb_copy_tag(tag_lastoffset); /* Avoid processing this entry again. */ @@ -3419,7 +3424,8 @@ static int parse_changelog_line(int line_n, char *buf, void *parameters) int idx_id; long masterfd = (long)parameters; const int import_tags[] = { tag_playcount, tag_rating, tag_playtime, - tag_lastplayed, tag_commitid, tag_lastoffset }; + tag_lastplayed, tag_commitid, tag_lastelapsed, + tag_lastoffset }; int i; (void)line_n; 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 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year, tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, - tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastoffset, + tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastelapsed, + tag_lastoffset, /* Real tags end here, count them. */ TAG_COUNT, /* Virtual tags */ @@ -51,7 +52,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, #define IDX_BUF_DEPTH 64 /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ -#define TAGCACHE_MAGIC 0x5443480e +#define TAGCACHE_MAGIC 0x5443480f /* Dump store/restore header version 'TCSxx'. */ #define TAGCACHE_STATEFILE_MAGIC 0x54435301 @@ -107,10 +108,11 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, (1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \ (1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \ (1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \ - (1LU << tag_lastoffset) | (1LU << tag_virt_basename) | \ - (1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \ - (1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \ - (1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore)) + (1LU << tag_lastelapsed) | (1LU << tag_lastoffset) | \ + (1LU << tag_virt_basename) | (1LU << tag_virt_length_min) | \ + (1LU << tag_virt_length_sec) | (1LU << tag_virt_playtime_min) | \ + (1LU << tag_virt_playtime_sec) | (1LU << tag_virt_entryage) | \ + (1LU << tag_virt_autoscore)) #define TAGCACHE_IS_NUMERIC(tag) (BIT_N(tag) & TAGCACHE_NUMERIC_TAGS) 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) {"playcount", tag_playcount}, {"rating", tag_rating}, {"lastplayed", tag_lastplayed}, + {"lastelapsed", tag_lastelapsed}, {"lastoffset", tag_lastoffset}, {"commitid", tag_commitid}, {"entryage", tag_virt_entryage}, @@ -841,8 +842,16 @@ static void tagtree_buffer_event(void *data) #if CONFIG_CODEC == SWCODEC if (autoresume) { - /* Load current file resume offset if not already defined (by + /* Load current file resume info if not already defined (by another resume mechanism) */ + if (id3->elapsed == 0) + { + id3->elapsed = tagcache_get_numeric(&tcs, tag_lastelapsed); + + logf("tagtree_buffer_event: Set elapsed for %s to %lX\n", + str_or_empty(id3->title), id3->elapsed); + } + if (id3->offset == 0) { id3->offset = tagcache_get_numeric(&tcs, tag_lastoffset); @@ -940,12 +949,13 @@ static void tagtree_track_finish_event(void *data) #if CONFIG_CODEC == SWCODEC if (autoresume) { + unsigned long elapsed = auto_skip ? 0 : id3->elapsed; unsigned long offset = auto_skip ? 0 : id3->offset; - + tagcache_update_numeric(tagcache_idx, tag_lastelapsed, elapsed); tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset); - logf("tagtree_track_finish_event: Save offset for %s: %lX", - str_or_empty(id3->title), offset); + logf("tagtree_track_finish_event: Save resume for %s: %lX %lX", + str_or_empty(id3->title), elapsed, offset); } #endif } @@ -2034,7 +2044,7 @@ static int tagtree_play_folder(struct tree_context* c) c->selected_item = 0; gui_synclist_select_item(&tree_lists, c->selected_item); - playlist_start(c->selected_item,0); + playlist_start(c->selected_item, 0, 0); playlist_get_current()->num_inserted_tracks = 0; /* make warn on playlist erase work */ return 0; } 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) tree_get_filetypes(&filetypes, &filetypes_count); } -bool bookmark_play(char *resume_file, int index, int offset, int seed, - char *filename) +bool bookmark_play(char *resume_file, int index, unsigned long elapsed, + unsigned long offset, int seed, char *filename) { int i; char* suffix = strrchr(resume_file, '.'); @@ -1082,7 +1082,7 @@ bool bookmark_play(char *resume_file, int index, int offset, int seed, { if (global_settings.playlist_shuffle) playlist_shuffle(seed, -1); - playlist_start(index,offset); + playlist_start(index, elapsed, offset); started = true; } *slash='/'; @@ -1133,7 +1133,7 @@ bool bookmark_play(char *resume_file, int index, int offset, int seed, else return false; } - playlist_start(index,offset); + playlist_start(index, elapsed, offset); started = true; } } 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); void tree_flush(void); void tree_restore(void); -bool bookmark_play(char* resume_file, int index, int offset, int seed, - char *filename); +bool bookmark_play(char* resume_file, int index, unsigned long elapsed, + unsigned long offset, int seed, char *filename); extern struct gui_synclist tree_lists; #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 @@ void audio_init(void) INIT_ATTR; -void audio_play(long offset); +void audio_play(unsigned long elapsed, unsigned long offset); void audio_stop(void); /* Stops audio from serving playback and frees resources*/ 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) samplesdone = 0; - /* The main decoding loop */ if (ci->id3->offset) { - if (ci->seek_buffer(ci->id3->offset)) { - samplesdone = (ci->id3->offset / ci->id3->bytesperframe) * - A52_SAMPLESPERFRAME; - ci->set_elapsed(samplesdone/(ci->id3->frequency / 1000)); - } + sample_loc = (ci->id3->offset / ci->id3->bytesperframe) * + A52_SAMPLESPERFRAME; + param = ci->id3->offset; + } + else if (ci->id3->elapsed) { + sample_loc = ci->id3->elapsed/1000 * ci->id3->frequency; + param = sample_loc/A52_SAMPLESPERFRAME*ci->id3->bytesperframe; } else { - ci->seek_buffer(ci->id3->first_frame_offset); - ci->set_elapsed(0); + sample_loc = 0; + param = ci->id3->first_frame_offset; } + if (ci->seek_buffer(param)) { + samplesdone = sample_loc; + } + + ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); + + /* The main decoding loop */ + while (1) { enum codec_command_action action = ci->get_command(¶m); @@ -172,7 +181,8 @@ enum codec_status codec_run(void) if (action == CODEC_ACTION_SEEK_TIME) { sample_loc = param/1000 * ci->id3->frequency; - if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) { + if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)* + ci->id3->bytesperframe)) { samplesdone = sample_loc; ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); } 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) int consumed, packet_offset; int playback_on = -1; size_t resume_offset; + enum codec_command_action action; intptr_t param; - enum codec_command_action action = CODEC_ACTION_NULL; if (codec_init()) { return CODEC_ERROR; } + action = CODEC_ACTION_NULL; + param = ci->id3->elapsed; resume_offset = ci->id3->offset; ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); @@ -171,11 +173,14 @@ enum codec_status codec_run(void) samplesdone = 0; /* check for a mid-track resume and force a seek time accordingly */ - if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { - resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; + if (resume_offset) { + resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); /* put number of subpackets to skip in resume_offset */ resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); + } + + if (param > 0) { action = CODEC_ACTION_SEEK_TIME; } 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) uint32_t sbr_fac = 1; unsigned char c = 0; void *ret; + enum codec_command_action action; intptr_t param; bool empty_first_frame = false; @@ -82,6 +83,8 @@ enum codec_status codec_run(void) return CODEC_ERROR; } + action = CODEC_ACTION_NULL; + param = ci->id3->elapsed; file_offset = ci->id3->offset; ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); @@ -138,11 +141,16 @@ enum codec_status codec_run(void) sound_samples_done = 0; } NeAACDecPostSeekReset(decoder, i); + elapsed_time = (sound_samples_done * 10) / + (ci->id3->frequency / 100); + } else if (param) { + elapsed_time = param; + action = CODEC_ACTION_SEEK_TIME; } else { + elapsed_time = 0; sound_samples_done = 0; } - elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); if (i == 0) @@ -152,7 +160,8 @@ enum codec_status codec_run(void) /* The main decoding loop */ while (i < demux_res.num_sample_byte_sizes) { - enum codec_command_action action = ci->get_command(¶m); + if (action == CODEC_ACTION_NULL) + action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; @@ -180,6 +189,8 @@ enum codec_status codec_run(void) ci->seek_complete(); } + action = CODEC_ACTION_NULL; + /* There can be gaps between chunks, so skip ahead if needed. It * doesn't seem to happen much, but it probably means that a * "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) codec_set_replaygain(ci->id3); /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + param = ci->id3->elapsed; bytesdone = ci->id3->offset; /* assume the AIFF header is less than 1024 bytes */ @@ -270,10 +271,20 @@ enum codec_status codec_run(void) ci->advance_buffer(firstblockposn); /* make sure we're at the correct offset */ - if (bytesdone > (uint32_t) firstblockposn) { + if (bytesdone > (uint32_t) firstblockposn || param) { + uint32_t seek_val; + int seek_mode; + + if (bytesdone) { + seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone); + seek_mode = PCM_SEEK_POS; + } else { + seek_val = param; + seek_mode = PCM_SEEK_TIME; + } + /* Round down to previous block */ - struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, - PCM_SEEK_POS, NULL); + struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, NULL); if (newpos->pos > format.numbytes) 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) demux_res_t demux_res; stream_t input_stream; uint32_t samplesdone; - uint32_t elapsedtime = 0; + uint32_t elapsedtime; int samplesdecoded; unsigned int i; unsigned char* buffer; @@ -71,9 +71,9 @@ enum codec_status codec_run(void) stream_create(&input_stream,ci); - /* Read from ci->id3->offset before calling qtmovie_read. */ - samplesdone = (uint32_t)(((uint64_t)(ci->id3->offset) * ci->id3->frequency) / - (ci->id3->bitrate*128)); + /* Read resume info before calling qtmovie_read. */ + elapsedtime = ci->id3->elapsed; + samplesdone = ci->id3->offset; /* if qtmovie_read returns successfully, the stream is up to * the movie data, which can be used directly by the decoder */ @@ -87,16 +87,24 @@ enum codec_status codec_run(void) /* Set i for first frame, seek to desired sample position for resuming. */ i=0; - if (samplesdone > 0) { - if (m4a_seek(&demux_res, &input_stream, samplesdone, + + if (elapsedtime || samplesdone) { + if (samplesdone) { + samplesdone = + (uint32_t)((uint64_t)samplesdone*ci->id3->frequency / + (ci->id3->bitrate*128)); + } + else { + samplesdone = (elapsedtime/10) * (ci->id3->frequency/100); + } + + if (!m4a_seek(&demux_res, &input_stream, samplesdone, &samplesdone, (int*) &i)) { - elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100); - ci->set_elapsed(elapsedtime); - } else { samplesdone = 0; } } + elapsedtime = (samplesdone*10)/(ci->id3->frequency/100); ci->set_elapsed(elapsedtime); /* The main decoding loop */ @@ -106,9 +114,6 @@ enum codec_status codec_run(void) if (action == CODEC_ACTION_HALT) break; - /* Request the required number of bytes from the input buffer */ - buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE); - /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { 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) int res; int firstbyte; size_t resume_offset; + enum codec_command_action action; intptr_t param; if (codec_init()) { @@ -162,8 +163,12 @@ enum codec_status codec_run(void) return CODEC_ERROR; } + action = CODEC_ACTION_NULL; + param = 0; + /* Remember the resume position - when the codec is opened, the playback engine will reset it. */ + elapsedtime = ci->id3->elapsed; resume_offset = ci->id3->offset; ci->seek_buffer(0); @@ -213,14 +218,21 @@ enum codec_status codec_run(void) ape_resume(&ape_ctx, resume_offset, ¤tframe, &samplesdone, &samplestoskip, &firstbyte); - } else { + elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); + } + else { currentframe = 0; samplesdone = 0; samplestoskip = 0; firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ + + if (elapsedtime) { + /* Resume by simulated seeking */ + param = elapsedtime; + action = CODEC_ACTION_SEEK_TIME; + } } - elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); ci->set_elapsed(elapsedtime); /* Initialise the buffer */ @@ -247,36 +259,44 @@ frame_start: /* Decode the frame a chunk at a time */ while (nblocks > 0) { - enum codec_command_action action = ci->get_command(¶m); + if (action == CODEC_ACTION_NULL) + action = ci->get_command(¶m); - if (action == CODEC_ACTION_HALT) - goto done; + if (action != CODEC_ACTION_NULL) { + if (action == CODEC_ACTION_HALT) + goto done; - /* Deal with any pending seek requests */ - if (action == CODEC_ACTION_SEEK_TIME) - { - if (ape_calc_seekpos(&ape_ctx, - (param/10) * (ci->id3->frequency/100), - ¤tframe, - &newfilepos, - &samplestoskip)) + /* Deal with any pending seek requests */ + if (action == CODEC_ACTION_SEEK_TIME) { - samplesdone = currentframe * ape_ctx.blocksperframe; + if (ape_calc_seekpos(&ape_ctx, + (param/10) * (ci->id3->frequency/100), + ¤tframe, + &newfilepos, + &samplestoskip)) + { + samplesdone = currentframe * ape_ctx.blocksperframe; - /* APE's bytestream is weird... */ - firstbyte = 3 - (newfilepos & 3); - newfilepos &= ~3; + /* APE's bytestream is weird... */ + firstbyte = 3 - (newfilepos & 3); + newfilepos &= ~3; - ci->seek_buffer(newfilepos); - inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); + ci->seek_buffer(newfilepos); + inbuffer = ci->request_buffer(&bytesleft, + INPUT_CHUNKSIZE); + + elapsedtime = (samplesdone*10)/ + (ape_ctx.samplerate/100); + ci->set_elapsed(elapsedtime); + ci->seek_complete(); + action = CODEC_ACTION_NULL; + goto frame_start; /* Sorry... */ + } - elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); - ci->set_elapsed(elapsedtime); ci->seek_complete(); - goto frame_start; /* Sorry... */ } - ci->seek_complete(); + action = CODEC_ACTION_NULL; } 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) return CODEC_ERROR; } + param = ci->id3->elapsed; + codec_set_replaygain(ci->id3); int bytes_done =0; @@ -86,8 +88,6 @@ enum codec_status codec_run(void) ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); bytesPerSample = 4; } - /* reset eleapsed */ - ci->set_elapsed(0); song = asap.module_info->default_song; duration = asap.module_info->durations[song]; @@ -100,6 +100,11 @@ enum codec_status codec_run(void) ASAP_PlaySong(&asap, song, duration); ASAP_MutePokeyChannels(&asap, 0); + if (param) + goto resume_start; + + ci->set_elapsed(0); + /* The main decoder loop */ while (1) { enum codec_command_action action = ci->get_command(¶m); @@ -108,6 +113,7 @@ enum codec_status codec_run(void) break; if (action == CODEC_ACTION_SEEK_TIME) { + resume_start: /* New time is ready in param */ /* 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) int elapsed = 0; size_t resume_offset; intptr_t param; - enum codec_command_action action = CODEC_ACTION_NULL; + enum codec_command_action action; if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } + action = CODEC_ACTION_NULL; + param = ci->id3->elapsed; resume_offset = ci->id3->offset; codec_set_replaygain(ci->id3); @@ -79,11 +81,13 @@ enum codec_status codec_run(void) frame_counter = 0; /* check for a mid-track resume and force a seek time accordingly */ - if(resume_offset > ci->id3->first_frame_offset) { - resume_offset -= ci->id3->first_frame_offset; + if (resume_offset) { + resume_offset -= MIN(resume_offset, ci->id3->first_frame_offset); /* calculate resume_offset in frames */ - resume_offset = (int)resume_offset / FRAMESIZE; - param = (int)resume_offset * ((FRAMESIZE * 8)/BITRATE); + param = (resume_offset/FRAMESIZE) * ((FRAMESIZE * 8)/BITRATE); + } + + if ((unsigned long)param) { action = CODEC_ACTION_SEEK_TIME; } else { @@ -100,11 +104,9 @@ enum codec_status codec_run(void) if (action == CODEC_ACTION_HALT) break; - bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE); - if (action == CODEC_ACTION_SEEK_TIME) { /* Do not allow seeking beyond the file's length */ - if ((unsigned) param > ci->id3->length) { + if ((unsigned long) param > ci->id3->length) { ci->set_elapsed(ci->id3->length); ci->seek_complete(); break; @@ -123,7 +125,6 @@ enum codec_status codec_run(void) seek_frame_offset = (param * BITRATE) / (8 * FRAMESIZE); frame_counter = seek_frame_offset; ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE); - bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE); elapsed = param; ci->set_elapsed(elapsed); ci->seek_complete(); @@ -131,6 +132,8 @@ enum codec_status codec_run(void) action = CODEC_ACTION_NULL; + bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE); + res = atrac3_decode_frame(FRAMESIZE, &q, &datasize, bit_buffer, FRAMESIZE); 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) uint8_t *bit_buffer; uint16_t fs,sps,h; uint32_t packet_count; - int scrambling_unit_size, num_units, elapsed = 0; + int scrambling_unit_size, num_units, elapsed; int playback_on = -1; size_t resume_offset; intptr_t param; - enum codec_command_action action = CODEC_ACTION_NULL; + enum codec_command_action action; if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } + action = CODEC_ACTION_NULL; + elapsed = ci->id3->elapsed; resume_offset = ci->id3->offset; codec_set_replaygain(ci->id3); @@ -98,15 +100,20 @@ enum codec_status codec_run(void) } /* check for a mid-track resume and force a seek time accordingly */ - if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { - resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; + if(resume_offset) { + resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); num_units = (int)resume_offset / scrambling_unit_size; /* put number of subpackets to skip in resume_offset */ resume_offset /= (sps + PACKET_HEADER_SIZE); - param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); + elapsed = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); + } + + if (elapsed > 0) { + param = elapsed; action = CODEC_ACTION_SEEK_TIME; } else { + elapsed = 0; ci->set_elapsed(0); } @@ -151,6 +158,7 @@ seek_start : /* Seek to the start of the track */ if (param == 0) { + elapsed = 0; ci->set_elapsed(0); ci->seek_complete(); 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) codec_set_replaygain(ci->id3); /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + param = ci->id3->elapsed; bytesdone = ci->id3->offset; ci->memset(&format, 0, sizeof(struct pcm_format)); @@ -236,10 +237,20 @@ enum codec_status codec_run(void) } /* make sure we're at the correct offset */ - if (bytesdone > (uint32_t) firstblockposn) { + if (bytesdone > (uint32_t) firstblockposn || param) { + uint32_t seek_val; + int seek_mode; + + if (bytesdone) { + seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone); + seek_mode = PCM_SEEK_POS; + } else { + seek_val = param; + seek_mode = PCM_SEEK_TIME; + } + /* Round down to previous block */ - struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, - PCM_SEEK_POS, NULL); + struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, NULL); if (newpos->pos > format.numbytes) 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) /* reset values */ track = is_multitrack = 0; elapsed_time = 0; + param = ci->id3->elapsed; DEBUGF("AY: next_track\n"); if (codec_init()) { @@ -87,6 +88,10 @@ enum codec_status codec_run(void) is_multitrack = 1; } + if (param) { + goto resume_start; + } + next_track: set_codec_track(track, is_multitrack); @@ -98,6 +103,7 @@ next_track: break; if (action == CODEC_ACTION_SEEK_TIME) { + resume_start: if (is_multitrack) { track = param/1000; 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) uint32_t packet_count; int scrambling_unit_size, num_units; size_t resume_offset; - intptr_t param = 0; - enum codec_command_action action = CODEC_ACTION_NULL; + intptr_t param; + enum codec_command_action action; if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } + action = CODEC_ACTION_NULL; + param = ci->id3->elapsed; resume_offset = ci->id3->offset; codec_set_replaygain(ci->id3); @@ -97,12 +99,15 @@ enum codec_status codec_run(void) } /* check for a mid-track resume and force a seek time accordingly */ - if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { - resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; + if(resume_offset) { + resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); num_units = (int)resume_offset / scrambling_unit_size; /* put number of subpackets to skip in resume_offset */ resume_offset /= (sps + PACKET_HEADER_SIZE); param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); + } + + if (param) { action = CODEC_ACTION_SEEK_TIME; } 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) return CODEC_ERROR; } - /* Need to save offset for later use (cleared indirectly by flac_init) */ + /* Need to save resume for later use (cleared indirectly by flac_init) */ + elapsedtime = ci->id3->elapsed; samplesdone = ci->id3->offset; if (!flac_init(&fc,ci->id3->first_frame_offset)) { @@ -481,9 +482,16 @@ enum codec_status codec_run(void) STEREO_MONO : STEREO_NONINTERLEAVED); codec_set_replaygain(ci->id3); - flac_seek_offset(&fc, samplesdone); - samplesdone=fc.samplenumber+fc.blocksize; - elapsedtime=((uint64_t)samplesdone*1000)/(ci->id3->frequency); + if (samplesdone || !elapsedtime) { + flac_seek_offset(&fc, samplesdone); + samplesdone=fc.samplenumber+fc.blocksize; + elapsedtime=((uint64_t)samplesdone*1000)/(ci->id3->frequency); + } + else if (!flac_seek(&fc,(uint32_t)((uint64_t)elapsedtime + *ci->id3->frequency/1000))) { + elapsedtime = 0; + } + ci->set_elapsed(elapsedtime); /* 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) if (gbs_emu.m3u.size > 0) gbs_emu.track_count = gbs_emu.m3u.size; + if (ci->id3->elapsed) { + track = ci->id3->elapsed/1000; + if (track >= gbs_emu.track_count) return CODEC_OK; + } + next_track: set_codec_track(track); 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) if (hes_emu.m3u.size > 0) hes_emu.track_count = hes_emu.m3u.size; + if (ci->id3->elapsed) { + track = ci->id3->elapsed/1000; + if (track >= hes_emu.track_count) return CODEC_OK; + } + next_track: set_codec_track(track); 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) if (kss_emu.m3u.size > 0) kss_emu.track_count = kss_emu.m3u.size; + if (ci->id3->elapsed) { + track = ci->id3->elapsed/1000; + if (track >= kss_emu.track_count) return CODEC_OK; + } + next_track: set_codec_track(track); 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) loadmod(modfile); /* The main decoder loop */ - ci->set_elapsed(0); +#if 0 + /* Needs to be a bit more elaborate or critical stuff is missed */ + if (ci->id3->elapsed) { + modplayer.patterntableposition = ci->id3->elapsed/1000; + modplayer.currentline = 0; + } +#endif + + ci->set_elapsed(modplayer.patterntableposition*1000); + bytesdone = 0; old_patterntableposition = 0; 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) current_frequency = ci->id3->frequency; codec_set_replaygain(ci->id3); + if (!ci->id3->offset && ci->id3->elapsed) { + /* Have elapsed time but not offset */ + ci->id3->offset = get_file_pos(ci->id3->elapsed); + } + if (ci->id3->offset) { ci->seek_buffer(ci->id3->offset); 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) * sample seek position from the file offset, the sampling frequency and * the bitrate. As the saved position is exactly calculated the reverse way * there is no loss of information except rounding. */ + elapsed_time = ci->id3->elapsed; samplesdone = 100 * (((mpc_uint64_t)ci->id3->offset * frequency) / byterate); /* Set up digital signal processing for correct number of channels */ @@ -122,19 +123,24 @@ enum codec_status codec_run(void) codec_set_replaygain(ci->id3); - /* Resume to saved sample offset. */ - elapsed_time = 0; - - if (samplesdone > 0) + if (samplesdone > 0 || elapsed_time) { - if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK) + mpc_int64_t new_offset = samplesdone; + + if (new_offset <= 0) + new_offset = (elapsed_time/10)*frequency; /* by time */ + + /* Resume to sample offset. */ + if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK) { - elapsed_time = (samplesdone*10)/frequency; + samplesdone = new_offset; } else { samplesdone = 0; } + + elapsed_time = (samplesdone*10)/frequency; } 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) track = is_multitrack = 0; elapsed_time = 0; + param = ci->id3->elapsed; DEBUGF("NSF: next_track\n"); if (codec_init()) { @@ -85,6 +86,10 @@ enum codec_status codec_run(void) if (nsf_emu.track_count > 1) is_multitrack = 1; + if (param) { + goto resume_start; + } + next_track: set_codec_track(track, is_multitrack); @@ -96,6 +101,7 @@ next_track: break; if (action == CODEC_ACTION_SEEK_TIME) { + resume_start: if (is_multitrack) { track = param/1000; 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) enum codec_status codec_run(void) { int error = CODEC_ERROR; + enum codec_command_action action; intptr_t param; ogg_sync_state oy; ogg_page og; @@ -325,13 +326,17 @@ enum codec_status codec_run(void) OpusDecoder *st = NULL; OpusHeader header; int ret; - unsigned long strtoffset = ci->id3->offset; + unsigned long strtoffset; int skip = 0; int64_t seek_target; uint64_t granule_pos; ogg_malloc_init(); + action = CODEC_ACTION_NULL; + param = ci->id3->elapsed; + strtoffset = ci->id3->offset; + global_stack = 0; #if defined(CPU_COLDFIRE) @@ -351,28 +356,40 @@ enum codec_status codec_run(void) ci->seek_buffer(0); ci->set_elapsed(0); + if (!strtoffset && param) { + action = CODEC_ACTION_SEEK_TIME; + } + + goto next_page; + while (1) { - enum codec_command_action action = ci->get_command(¶m); + if (action == CODEC_ACTION_NULL) + action = ci->get_command(¶m); - if (action == CODEC_ACTION_HALT) - break; + if (action != CODEC_ACTION_NULL) { + if (action == CODEC_ACTION_HALT) + break; - if (action == CODEC_ACTION_SEEK_TIME) { - if (st != NULL) { - /* calculate granule to seek to (including seek rewind) */ - seek_target = (48LL * param) + header.preskip; - skip = MIN(seek_target, SEEK_REWIND); - seek_target -= skip; + if (action == CODEC_ACTION_SEEK_TIME) { + if (st != NULL) { + /* calculate granule to seek to (including seek rewind) */ + seek_target = (48LL * param) + header.preskip; + skip = MIN(seek_target, SEEK_REWIND); + seek_target -= skip; - LOGF("Opus seek page:%lld,%lld,%ld\n", - seek_target, page_granule, (long)param); - speex_seek_page_granule(seek_target, page_granule, &oy, &os); + LOGF("Opus seek page:%lld,%lld,%ld\n", + seek_target, page_granule, (long)param); + speex_seek_page_granule(seek_target, page_granule, &oy, &os); + } + + ci->set_elapsed(param); + ci->seek_complete(); } - ci->set_elapsed(param); - ci->seek_complete(); + action = CODEC_ACTION_NULL; } + next_page: /*Get the ogg buffer for writing*/ if (get_more_data(&oy) < 1) { 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) unsigned char c = 0; /* channels */ int playback_on = -1; size_t resume_offset; + enum codec_command_action action; intptr_t param; - enum codec_command_action action = CODEC_ACTION_NULL; if (codec_init()) { DEBUGF("FAAD: Codec init error\n"); return CODEC_ERROR; } + action = CODEC_ACTION_NULL; + param = ci->id3->elapsed; resume_offset = ci->id3->offset; ci->memset(&rmctx,0,sizeof(RMContext)); @@ -104,15 +106,21 @@ enum codec_status codec_run(void) } /* check for a mid-track resume and force a seek time accordingly */ - if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { - resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; + if (resume_offset) { + resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); /* put number of subpackets to skip in resume_offset */ resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); + } + + if (param > 0) { action = CODEC_ACTION_SEEK_TIME; } - ci->set_elapsed(0); - ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); + else { + /* Seek to the first packet */ + ci->set_elapsed(0); + ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); + } /* The main decoding loop */ while (1) { @@ -124,7 +132,7 @@ enum codec_status codec_run(void) if (action == CODEC_ACTION_SEEK_TIME) { /* Do not allow seeking beyond the file's length */ - if ((unsigned) param > ci->id3->length) { + if ((unsigned long)param > ci->id3->length) { ci->set_elapsed(ci->id3->length); ci->seek_complete(); break; @@ -164,6 +172,7 @@ enum codec_status codec_run(void) ci->advance_buffer(pkt.length); } + ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE); buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000); 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) if (sgc_emu.m3u.size > 0) sgc_emu.track_count = sgc_emu.m3u.size; + if (ci->id3->elapsed) { + track = ci->id3->elapsed/1000; + if (track >= sgc_emu.track_count) return CODEC_OK; + } + next_track: set_codec_track(track); 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) unsigned char subSongsMax, subSong, song_speed; unsigned char *sidfile = NULL; intptr_t param; + bool resume; if (codec_init()) { return CODEC_ERROR; @@ -1269,15 +1270,10 @@ enum codec_status codec_run(void) return CODEC_ERROR; } - c64Init(SAMPLE_RATE); - LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, - &subSongsMax, &subSong, &song_speed, (unsigned short)filesize); - sidPoke(24, 15); /* Turn on full volume */ - cpuJSR(init_addr, subSong); /* Start the song initialize */ + param = ci->id3->elapsed; + resume = param != 0; - - /* Set the elapsed time to the current subsong (in seconds) */ - ci->set_elapsed(subSong*1000); + goto sid_start; /* The main decoder loop */ while (1) { @@ -1287,20 +1283,26 @@ enum codec_status codec_run(void) break; if (action == CODEC_ACTION_SEEK_TIME) { + sid_start: /* New time is ready in param */ /* Start playing from scratch */ c64Init(SAMPLE_RATE); LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, - &subSongsMax, &subSong, &song_speed, (unsigned short)filesize); + &subSongsMax, &subSong, &song_speed, + (unsigned short)filesize); sidPoke(24, 15); /* Turn on full volume */ - subSong = param / 1000; /* Now use the current seek time in seconds as subsong */ + if (!resume || (resume && param)) + subSong = param / 1000; /* Now use the current seek time in + seconds as subsong */ cpuJSR(init_addr, subSong); /* Start the song initialize */ nSamplesToRender = 0; /* Start the rendering from scratch */ /* Set the elapsed time to the current subsong (in seconds) */ ci->set_elapsed(subSong*1000); ci->seek_complete(); + + resume = false; } 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) codec_set_replaygain(ci->id3); - /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + /* Need to save resume for later use (cleared indirectly by advance_buffer) */ + param = ci->id3->elapsed; bytesdone = ci->id3->offset; decodedsamples = 0; @@ -408,11 +409,21 @@ enum codec_status codec_run(void) ci->seek_buffer(firstblockposn); /* make sure we're at the correct offset */ - if (bytesdone > (uint32_t) firstblockposn) - { + if (bytesdone > (uint32_t) firstblockposn || param) { + uint32_t seek_val; + int seek_mode; + + if (bytesdone) { + seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone); + seek_mode = PCM_SEEK_POS; + } else { + seek_val = param; + seek_mode = PCM_SEEK_TIME; + } + /* Round down to previous block */ - struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, - PCM_SEEK_POS, &read_buffer); + struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, + &read_buffer); if (newpos->pos > format.numbytes) 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) int error = CODEC_ERROR; SpeexBits bits; - int eof = 0; spx_ogg_sync_state oy; spx_ogg_page og; spx_ogg_packet op; @@ -403,9 +402,10 @@ enum codec_status codec_run(void) int packet_count = 0; int lookahead; int headerssize = 0; - unsigned long strtoffset = ci->id3->offset; + unsigned long strtoffset; void *st = NULL; int j = 0; + enum codec_command_action action; intptr_t param; memset(&bits, 0, sizeof(bits)); @@ -416,6 +416,10 @@ enum codec_status codec_run(void) goto exit; } + action = CODEC_ACTION_NULL; + param = ci->id3->elapsed; + strtoffset = ci->id3->offset; + ci->seek_buffer(0); ci->set_elapsed(0); @@ -425,29 +429,39 @@ enum codec_status codec_run(void) codec_set_replaygain(ci->id3); - eof = 0; - while (!eof) { - enum codec_command_action action = ci->get_command(¶m); + if (!strtoffset && param) { + action = CODEC_ACTION_SEEK_TIME; + } - if (action == CODEC_ACTION_HALT) - break; + goto next_page; - /*seek (seeks to the page before the position) */ - if (action == CODEC_ACTION_SEEK_TIME) { - if(samplerate!=0&&packet_count>1){ - LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n", - ((spx_int64_t)param/1000) * - (spx_int64_t)samplerate, - page_granule, (long)param, - (page_granule/samplerate)*1000, samplerate); + while (1) { + if (action == CODEC_ACTION_NULL) + action = ci->get_command(¶m); - speex_seek_page_granule(((spx_int64_t)param/1000) * - (spx_int64_t)samplerate, - page_granule, &oy, headerssize); + if (action != CODEC_ACTION_NULL) { + if (action == CODEC_ACTION_HALT) + break; + + /*seek (seeks to the page before the position) */ + if (action == CODEC_ACTION_SEEK_TIME) { + if(samplerate!=0&&packet_count>1){ + LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n", + ((spx_int64_t)param/1000) * + (spx_int64_t)samplerate, + page_granule, (long)param, + (page_granule/samplerate)*1000, samplerate); + + speex_seek_page_granule(((spx_int64_t)param/1000) * + (spx_int64_t)samplerate, + page_granule, &oy, headerssize); + } + + ci->set_elapsed(param); + ci->seek_complete(); } - ci->set_elapsed(param); - ci->seek_complete(); + action = CODEC_ACTION_NULL; } 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) decodedsamples = 0; endofstream = 0; - if (ci->id3->offset > 0) + if (ci->id3->offset || ci->id3->elapsed) { - /* Need to save offset for later use (cleared indirectly by advance_buffer) */ - new_pos = set_position(ci->id3->offset, TTA_SEEK_POS); + /* Need to save offset for later use (cleared indirectly by + advance_buffer) */ + unsigned int pos = ci->id3->offset; + enum tta_seek_type type = TTA_SEEK_POS; + + if (!pos) { + pos = ci->id3->elapsed / SEEK_STEP; + type = TTA_SEEK_TIME; + } + + new_pos = set_position(pos, type); + if (new_pos >= 0) decodedsamples = new_pos; } 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) Vgm_start_track(&vgm_emu); - ci->set_elapsed(0); + if (ci->id3->elapsed != 0) + Track_seek(&vgm_emu, ci->id3->elapsed); + + codec_update_elapsed(); codec_update_fade(); /* 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) long n; int current_section; int previous_section; - int eof; ogg_int64_t vf_offsets[2]; ogg_int64_t vf_dataoffsets; ogg_uint32_t vf_serialnos; @@ -193,16 +192,17 @@ enum codec_status codec_run(void) if (ci->id3->offset) { ci->seek_buffer(ci->id3->offset); ov_raw_seek(&vf, ci->id3->offset); - ci->set_elapsed(ov_time_tell(&vf)); ci->set_offset(ov_raw_tell(&vf)); } - else { - ci->set_elapsed(0); + else if (ci->id3->elapsed) { + ov_time_seek(&vf, ci->id3->elapsed); } + ci->set_elapsed(ov_time_tell(&vf)); + previous_section = -1; - eof = 0; - while (!eof) { + + while (1) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) @@ -230,7 +230,7 @@ enum codec_status codec_run(void) } if (n == 0) { - eof = 1; + break; } else if (n < 0) { DEBUGF("Vorbis: Error decoding frame\n"); } 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) codec_set_replaygain(ci->id3); - /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + /* Need to save resume for later use (cleared indirectly by advance_buffer) */ + param = ci->id3->elapsed; bytesdone = ci->id3->offset; ci->seek_buffer(0); @@ -123,10 +124,21 @@ enum codec_status codec_run(void) ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); /* make sure we're at the correct offset */ - if (bytesdone > (uint32_t) firstblockposn) { + if (bytesdone > (uint32_t) firstblockposn || param) { + uint32_t seek_val; + int seek_mode; + + if (bytesdone) { + seek_val = bytesdone - MIN((uint32_t )firstblockposn, bytesdone); + seek_mode = PCM_SEEK_POS; + } else { + seek_val = param; + seek_mode = PCM_SEEK_TIME; + } + /* Round down to previous block */ - struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, - PCM_SEEK_POS, &read_buffer); + struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, + &read_buffer); if (newpos->pos > format.numbytes) { 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) codec_set_replaygain(ci->id3); - /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + /* Need to save resume for later use (cleared indirectly by advance_buffer) */ + param = ci->id3->elapsed; bytesdone = ci->id3->offset; /* get RIFF chunk header */ @@ -361,10 +362,21 @@ enum codec_status codec_run(void) } /* make sure we're at the correct offset */ - if (bytesdone > (uint32_t) firstblockposn) { + if (bytesdone > (uint32_t) firstblockposn || param) { + uint32_t seek_val; + int seek_mode; + + if (bytesdone) { + seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone); + seek_mode = PCM_SEEK_POS; + } else { + seek_val = param; + seek_mode = PCM_SEEK_TIME; + } + /* Round down to previous block */ - struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, - PCM_SEEK_POS, &read_buffer); + struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, + &read_buffer); if (newpos->pos > format.numbytes) 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) codec_set_replaygain(ci->id3); /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + param = ci->id3->elapsed; bytesdone = ci->id3->offset; /* get RIFF chunk header */ @@ -363,10 +364,22 @@ enum codec_status codec_run(void) } /* make sure we're at the correct offset */ - if (bytesdone > (uint32_t) firstblockposn) { + if (bytesdone > (uint32_t) firstblockposn || param) { + uint32_t seek_val; + int seek_mode; + + /* we prefer offset resume */ + if (bytesdone > (uint32_t) firstblockposn) { + seek_val = bytesdone - firstblockposn; + seek_mode = PCM_SEEK_POS; + } else { + seek_val = param; + seek_mode = PCM_SEEK_TIME; + } + /* Round down to previous block */ - struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, - PCM_SEEK_POS, &read_buffer); + struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, + &read_buffer); if (newpos->pos > format.numbytes) { 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) int bps; */ int nchans, sr_100; + unsigned long offset; intptr_t param; if (codec_init()) return CODEC_ERROR; - ci->seek_buffer (ci->id3->offset); + param = ci->id3->elapsed; + offset = ci->id3->offset; + + ci->seek_buffer (offset); /* Create a decoder instance */ wpc = WavpackOpenFileInput (read_callback, error); @@ -75,7 +79,12 @@ enum codec_status codec_run(void) ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO); sr_100 = ci->id3->frequency / 100; - ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); + if (!offset && param) { + goto resume_start; /* resume by elapsed */ + } + else { + ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); + } /* The main decoder loop */ @@ -87,6 +96,7 @@ enum codec_status codec_run(void) break; if (action == CODEC_ACTION_SEEK_TIME) { + resume_start:; int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10; int n, d, skip; 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) int audiobufsize; int packetlength = 0; int errcount = 0; + enum codec_command_action action; intptr_t param; /* Remember the resume position - when the codec is opened, the playback engine will reset it. */ + elapsedtime = ci->id3->elapsed; resume_offset = ci->id3->offset; restart_track: + action = CODEC_ACTION_NULL; /* Proper reset of the decoder context. */ memset(&wmadec, 0, sizeof(wmadec)); @@ -78,13 +81,20 @@ restart_track: return CODEC_ERROR; } - if (resume_offset > ci->id3->first_frame_offset) + if (resume_offset > ci->id3->first_frame_offset || elapsedtime) { - /* Get start of current packet */ - int packet_offset = (resume_offset - ci->id3->first_frame_offset) - % wfx.packet_size; - ci->seek_buffer(resume_offset - packet_offset); - elapsedtime = asf_get_timestamp(&i); + if (resume_offset) { + /* Get start of current packet */ + int packet_offset = (resume_offset - + MIN(resume_offset, ci->id3->first_frame_offset)) + % wfx.packet_size; + ci->seek_buffer(resume_offset - packet_offset); + elapsedtime = asf_get_timestamp(&i); + } + else { + param = elapsedtime; + action = CODEC_ACTION_SEEK_TIME; + } } else { @@ -104,7 +114,8 @@ restart_track: /* The main decoding loop */ while (res >= 0) { - enum codec_command_action action = ci->get_command(¶m); + if (action == CODEC_ACTION_NULL) + action = ci->get_command(¶m); if (action != CODEC_ACTION_NULL) { @@ -126,6 +137,7 @@ restart_track: if (param == 0) { ci->set_elapsed(0); ci->seek_complete(); + elapsedtime = 0; goto restart_track; /* Pretend you never saw this... */ } @@ -140,6 +152,8 @@ restart_track: ci->set_elapsed(elapsedtime); ci->seek_complete(); } + + action = CODEC_ACTION_NULL; } 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) int size; /* Size of the input frame to the decoder */ intptr_t param; + elapsedtime = ci->id3->elapsed; + restart_track: if (codec_init()) { LOGF("(WMA PRO) Error: Error initialising codec\n"); @@ -75,11 +77,17 @@ restart_track: return CODEC_ERROR; } - /* Now advance the file position to the first frame */ - ci->seek_buffer(ci->id3->first_frame_offset); + if (elapsedtime) { + elapsedtime = asf_seek(elapsedtime, &wfx); + if (elapsedtime < 1) + return CODEC_OK; + } + else { + /* Now advance the file position to the first frame */ + ci->seek_buffer(ci->id3->first_frame_offset); + } - elapsedtime = 0; - ci->set_elapsed(0); + ci->set_elapsed(elapsedtime); /* The main decoding loop */ @@ -95,6 +103,7 @@ restart_track: if (param == 0) { ci->set_elapsed(0); ci->seek_complete(); + elapsedtime = 0; goto restart_track; /* Pretend you never saw this... */ } 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) { uint32_t elapsedtime; asf_waveformatex_t wfx; /* Holds the stream properties */ - size_t resume_offset; int res; /* Return values from asf_read_packet() and decode_packet() */ uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */ int audiobufsize; /* Payload size */ @@ -76,8 +75,8 @@ enum codec_status codec_run(void) int pktcnt = 0; /* Count of the packets played */ intptr_t param; - /* Remember the resume position */ - resume_offset = ci->id3->offset; + elapsedtime = ci->id3->elapsed; + restart_track: if (codec_init()) { LOGF("(WMA Voice) Error: Error initialising codec\n"); @@ -105,13 +104,17 @@ restart_track: return CODEC_ERROR; } - /* Now advance the file position to the first frame */ - ci->seek_buffer(ci->id3->first_frame_offset); - - elapsedtime = 0; - ci->set_elapsed(0); + if (elapsedtime) { + elapsedtime = asf_seek(elapsedtime, &wfx); + if (elapsedtime < 1) + return CODEC_OK; + } + else { + /* Now advance the file position to the first frame */ + ci->seek_buffer(ci->id3->first_frame_offset); + } - resume_offset = 0; + ci->set_elapsed(elapsedtime); /* The main decoding loop */ @@ -129,6 +132,7 @@ restart_track: if (param == 0) { ci->set_elapsed(0); ci->seek_complete(); + elapsedtime = 0; goto restart_track; /* Pretend you never saw this... */ } @@ -136,7 +140,7 @@ restart_track: if (elapsedtime < 1){ ci->set_elapsed(0); ci->seek_complete(); - goto next_track; + break; } ci->set_elapsed(elapsedtime);