summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/bookmark.c2
-rw-r--r--apps/filetree.c5
-rw-r--r--apps/gui/skin_engine/skin_parser.c6
-rw-r--r--apps/gui/skin_engine/skin_touchsupport.c1
-rw-r--r--apps/misc.c2
-rw-r--r--apps/mpeg.c60
-rw-r--r--apps/onplay.c2
-rw-r--r--apps/playback.c137
-rwxr-xr-xapps/playlist.c21
-rw-r--r--apps/playlist.h6
-rw-r--r--apps/playlist_viewer.c10
-rw-r--r--apps/plugin.h12
-rw-r--r--apps/plugins/alarmclock.c1
-rw-r--r--apps/plugins/alpine_cdc.c4
-rw-r--r--apps/plugins/lib/playback_control.c1
-rw-r--r--apps/plugins/lrcplayer.c1
-rw-r--r--apps/plugins/pictureflow/pictureflow.c2
-rw-r--r--apps/plugins/random_folder_advance_config.c2
-rw-r--r--apps/root_menu.c1
-rw-r--r--apps/settings.c11
-rw-r--r--apps/settings.h2
-rw-r--r--apps/settings_list.c1
-rw-r--r--apps/settings_list.h2
-rw-r--r--apps/tagcache.c12
-rw-r--r--apps/tagcache.h14
-rw-r--r--apps/tagtree.c20
-rw-r--r--apps/tree.c8
-rw-r--r--apps/tree.h4
-rw-r--r--firmware/export/audio.h2
-rw-r--r--lib/rbcodec/codecs/a52.c28
-rw-r--r--lib/rbcodec/codecs/a52_rm.c11
-rw-r--r--lib/rbcodec/codecs/aac.c15
-rw-r--r--lib/rbcodec/codecs/aiff.c17
-rw-r--r--lib/rbcodec/codecs/alac.c29
-rw-r--r--lib/rbcodec/codecs/ape.c70
-rw-r--r--lib/rbcodec/codecs/asap.c10
-rw-r--r--lib/rbcodec/codecs/atrac3_oma.c21
-rw-r--r--lib/rbcodec/codecs/atrac3_rm.c18
-rw-r--r--lib/rbcodec/codecs/au.c17
-rw-r--r--lib/rbcodec/codecs/ay.c6
-rw-r--r--lib/rbcodec/codecs/cook.c13
-rw-r--r--lib/rbcodec/codecs/flac.c16
-rw-r--r--lib/rbcodec/codecs/gbs.c5
-rw-r--r--lib/rbcodec/codecs/hes.c5
-rw-r--r--lib/rbcodec/codecs/kss.c5
-rw-r--r--lib/rbcodec/codecs/mod.c11
-rw-r--r--lib/rbcodec/codecs/mpa.c5
-rw-r--r--lib/rbcodec/codecs/mpc.c18
-rw-r--r--lib/rbcodec/codecs/nsf.c6
-rw-r--r--lib/rbcodec/codecs/opus.c47
-rw-r--r--lib/rbcodec/codecs/raac.c21
-rw-r--r--lib/rbcodec/codecs/sgc.c5
-rw-r--r--lib/rbcodec/codecs/sid.c22
-rw-r--r--lib/rbcodec/codecs/smaf.c21
-rw-r--r--lib/rbcodec/codecs/speex.c60
-rw-r--r--lib/rbcodec/codecs/tta.c16
-rw-r--r--lib/rbcodec/codecs/vgm.c5
-rw-r--r--lib/rbcodec/codecs/vorbis.c14
-rw-r--r--lib/rbcodec/codecs/vox.c20
-rw-r--r--lib/rbcodec/codecs/wav.c20
-rw-r--r--lib/rbcodec/codecs/wav64.c19
-rw-r--r--lib/rbcodec/codecs/wavpack.c14
-rwxr-xr-xlib/rbcodec/codecs/wma.c28
-rw-r--r--lib/rbcodec/codecs/wmapro.c17
-rw-r--r--lib/rbcodec/codecs/wmavoice.c24
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)
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 = &current_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(&param);
@@ -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(&param);
+ if (action == CODEC_ACTION_NULL)
+ action = ci->get_command(&param);
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,
&currentframe, &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(&param);
+ if (action == CODEC_ACTION_NULL)
+ action = ci->get_command(&param);
- 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),
- &currentframe,
- &newfilepos,
- &samplestoskip))
+ /* Deal with any pending seek requests */
+ if (action == CODEC_ACTION_SEEK_TIME)
{
- samplesdone = currentframe * ape_ctx.blocksperframe;
-
- /* APE's bytestream is weird... */
- firstbyte = 3 - (newfilepos & 3);
- newfilepos &= ~3;
-
- ci->seek_buffer(newfilepos);
- inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
+ if (ape_calc_seekpos(&ape_ctx,
+ (param/10) * (ci->id3->frequency/100),
+ &currentframe,
+ &newfilepos,
+ &samplestoskip))
+ {
+ samplesdone = currentframe * ape_ctx.blocksperframe;
+
+ /* APE's bytestream is weird... */
+ firstbyte = 3 - (newfilepos & 3);
+ newfilepos &= ~3;
+
+ 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(&param);
@@ -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(&param);
+ if (action == CODEC_ACTION_NULL)
+ action = ci->get_command(&param);
- 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(&param);
-
- 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);
+ if (!strtoffset && param) {
+ action = CODEC_ACTION_SEEK_TIME;
+ }
+
+ goto next_page;
+
+ while (1) {
+ if (action == CODEC_ACTION_NULL)
+ action = ci->get_command(&param);
+
+ 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(&param);
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(&param);
+ if (action == CODEC_ACTION_NULL)
+ action = ci->get_command(&param);
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);