diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2013-07-14 07:59:39 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2014-03-10 04:12:30 +0100 |
commit | 31b712286721dd606940c7b557d03e3f714b9604 (patch) | |
tree | 8c4a4cc32e9000ea721ebb23aa3c0129ca97bf53 /apps/playback.c | |
parent | dda54b85daa83b7803b4fb189ab45859f96ff3f9 (diff) | |
download | rockbox-31b712286721dd606940c7b557d03e3f714b9604.tar.gz rockbox-31b712286721dd606940c7b557d03e3f714b9604.zip |
Implement time-based resume and playback start.
This complements offset-based resume and playback start funcionality.
The implementation is global on both HWCODEC and SWCODEC.
Basically, if either the specified elapsed or offset are non-zero,
it indicates a mid-track resume.
To resume by time only, set elapsed to nonzero and offset to zero.
To resume by offset only, set offset to nonzero and elapsed to zero.
Which one the codec uses and which has priority is up to the codec;
however, using an elapsed time covers more cases:
* Codecs not able to use an offset such as VGM or other atomic
formats
* Starting playback at a nonzero elapsed time from a source that
contains no offset, such as a cuesheet
The change re-versions pretty much everything from tagcache to nvram.
Change-Id: Ic7aebb24e99a03ae99585c5e236eba960d163f38
Reviewed-on: http://gerrit.rockbox.org/516
Reviewed-by: Michael Sevakis <jethead71@rockbox.org>
Tested: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'apps/playback.c')
-rw-r--r-- | apps/playback.c | 137 |
1 files changed, 92 insertions, 45 deletions
diff --git a/apps/playback.c b/apps/playback.c index 5e234beb36..80a0585b17 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -151,6 +151,12 @@ enum audio_id3_types | |||
151 | }; | 151 | }; |
152 | static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */ | 152 | static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */ |
153 | 153 | ||
154 | struct audio_resume_info | ||
155 | { | ||
156 | unsigned long elapsed; | ||
157 | unsigned long offset; | ||
158 | }; | ||
159 | |||
154 | /* Peeking functions can yield and mess us up */ | 160 | /* Peeking functions can yield and mess us up */ |
155 | static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/ | 161 | static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/ |
156 | 162 | ||
@@ -325,7 +331,8 @@ enum audio_start_playback_flags | |||
325 | AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */ | 331 | AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */ |
326 | }; | 332 | }; |
327 | 333 | ||
328 | static void audio_start_playback(size_t offset, unsigned int flags); | 334 | static void audio_start_playback(const struct audio_resume_info *resume_info, |
335 | unsigned int flags); | ||
329 | static void audio_stop_playback(void); | 336 | static void audio_stop_playback(void); |
330 | static void buffer_event_buffer_low_callback(void *data); | 337 | static void buffer_event_buffer_low_callback(void *data); |
331 | static void buffer_event_rebuffer_callback(void *data); | 338 | static void buffer_event_rebuffer_callback(void *data); |
@@ -792,7 +799,11 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
792 | /* codec messages */ | 799 | /* codec messages */ |
793 | { Q_AUDIO_PLAY, Q_AUDIO_PLAY }, | 800 | { Q_AUDIO_PLAY, Q_AUDIO_PLAY }, |
794 | }; | 801 | }; |
802 | |||
803 | static struct audio_resume_info resume; | ||
804 | |||
795 | bool give_up = false; | 805 | bool give_up = false; |
806 | |||
796 | /* filebuflen is, at this point, the buffering.c buffer size, | 807 | /* filebuflen is, at this point, the buffering.c buffer size, |
797 | * i.e. the audiobuf except voice, scratch mem, pcm, ... */ | 808 | * i.e. the audiobuf except voice, scratch mem, pcm, ... */ |
798 | ssize_t extradata_size = old_size - filebuflen; | 809 | ssize_t extradata_size = old_size - filebuflen; |
@@ -813,7 +824,9 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
813 | 824 | ||
814 | 825 | ||
815 | /* TODO: Do it without stopping playback, if possible */ | 826 | /* TODO: Do it without stopping playback, if possible */ |
816 | long offset = audio_current_track()->offset; | 827 | struct mp3entry *id3 = audio_current_track(); |
828 | unsigned long elapsed = id3->elapsed; | ||
829 | unsigned long offset = id3->offset; | ||
817 | /* resume if playing */ | 830 | /* resume if playing */ |
818 | bool playing = (audio_status() == AUDIO_STATUS_PLAY); | 831 | bool playing = (audio_status() == AUDIO_STATUS_PLAY); |
819 | /* There's one problem with stoping and resuming: If it happens in a too | 832 | /* There's one problem with stoping and resuming: If it happens in a too |
@@ -825,10 +838,20 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
825 | * queue_post from the last call to get the correct offset. This also | 838 | * queue_post from the last call to get the correct offset. This also |
826 | * lets us conviniently remove the queue event so Q_AUDIO_PLAY is only | 839 | * lets us conviniently remove the queue event so Q_AUDIO_PLAY is only |
827 | * processed once. */ | 840 | * processed once. */ |
828 | bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, filter_list); | 841 | bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, |
842 | filter_list); | ||
829 | 843 | ||
830 | if (playing && offset > 0) /* current id3->offset is king */ | 844 | if (playing && ev.data != (intptr_t)&resume) |
831 | ev.data = offset; | 845 | { |
846 | resume = *(struct audio_resume_info *)ev.data; | ||
847 | |||
848 | /* current id3->elapsed/offset are king */ | ||
849 | if (elapsed > 0) | ||
850 | resume.elapsed = elapsed; | ||
851 | |||
852 | if (offset > 0) | ||
853 | resume.offset = offset; | ||
854 | } | ||
832 | 855 | ||
833 | /* don't call audio_hard_stop() as it frees this handle */ | 856 | /* don't call audio_hard_stop() as it frees this handle */ |
834 | if (thread_self() == audio_thread_id) | 857 | if (thread_self() == audio_thread_id) |
@@ -867,7 +890,7 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s | |||
867 | if (playing || play_queued) | 890 | if (playing || play_queued) |
868 | { | 891 | { |
869 | /* post, to make subsequent calls not break the resume position */ | 892 | /* post, to make subsequent calls not break the resume position */ |
870 | audio_queue_post(Q_AUDIO_PLAY, ev.data); | 893 | audio_queue_post(Q_AUDIO_PLAY, (intptr_t)&resume); |
871 | } | 894 | } |
872 | 895 | ||
873 | return BUFLIB_CB_OK; | 896 | return BUFLIB_CB_OK; |
@@ -1099,7 +1122,8 @@ static void audio_update_and_announce_next_track(const struct mp3entry *id3_next | |||
1099 | 1122 | ||
1100 | /* Bring the user current mp3entry up to date and set a new offset for the | 1123 | /* Bring the user current mp3entry up to date and set a new offset for the |
1101 | buffered metadata */ | 1124 | buffered metadata */ |
1102 | static void playing_id3_sync(struct track_info *user_info, off_t offset) | 1125 | static void playing_id3_sync(struct track_info *user_info, |
1126 | unsigned long elapsed, unsigned long offset) | ||
1103 | { | 1127 | { |
1104 | id3_mutex_lock(); | 1128 | id3_mutex_lock(); |
1105 | 1129 | ||
@@ -1113,9 +1137,14 @@ static void playing_id3_sync(struct track_info *user_info, off_t offset) | |||
1113 | 1137 | ||
1114 | id3_write(PLAYING_ID3, id3); | 1138 | id3_write(PLAYING_ID3, id3); |
1115 | 1139 | ||
1116 | if (offset < 0) | 1140 | if (elapsed == (unsigned long)-1) |
1117 | { | 1141 | { |
1118 | playing_id3->elapsed = e; | 1142 | playing_id3->elapsed = e; |
1143 | elapsed = 0; | ||
1144 | } | ||
1145 | |||
1146 | if (offset == (unsigned long)-1) | ||
1147 | { | ||
1119 | playing_id3->offset = o; | 1148 | playing_id3->offset = o; |
1120 | offset = 0; | 1149 | offset = 0; |
1121 | } | 1150 | } |
@@ -1123,7 +1152,10 @@ static void playing_id3_sync(struct track_info *user_info, off_t offset) | |||
1123 | pcm_play_unlock(); | 1152 | pcm_play_unlock(); |
1124 | 1153 | ||
1125 | if (id3) | 1154 | if (id3) |
1155 | { | ||
1156 | id3->elapsed = elapsed; | ||
1126 | id3->offset = offset; | 1157 | id3->offset = offset; |
1158 | } | ||
1127 | 1159 | ||
1128 | id3_mutex_unlock(); | 1160 | id3_mutex_unlock(); |
1129 | } | 1161 | } |
@@ -1299,19 +1331,16 @@ static bool audio_get_track_metadata(int offset, struct mp3entry *id3) | |||
1299 | return false; | 1331 | return false; |
1300 | } | 1332 | } |
1301 | 1333 | ||
1302 | /* Get a resume rewind adjusted offset from the ID3 */ | 1334 | /* Get resume rewind adjusted progress from the ID3 */ |
1303 | static unsigned long resume_rewind_adjusted_offset(const struct mp3entry *id3) | 1335 | static void resume_rewind_adjust_progress(const struct mp3entry *id3, |
1336 | unsigned long *elapsed, | ||
1337 | unsigned long *offset) | ||
1304 | { | 1338 | { |
1305 | unsigned long offset = id3->offset; | 1339 | unsigned int rewind = MAX(global_settings.resume_rewind, 0); |
1306 | size_t resume_rewind = global_settings.resume_rewind * | 1340 | unsigned long d_e = rewind*1000; |
1307 | id3->bitrate * (1000/8); | 1341 | *elapsed = id3->elapsed - MIN(id3->elapsed, d_e); |
1308 | 1342 | unsigned long d_o = rewind * id3->bitrate * (1000/8); | |
1309 | if (offset < resume_rewind) | 1343 | *offset = id3->offset - MIN(id3->offset, d_o); |
1310 | offset = 0; | ||
1311 | else | ||
1312 | offset -= resume_rewind; | ||
1313 | |||
1314 | return offset; | ||
1315 | } | 1344 | } |
1316 | 1345 | ||
1317 | /* Get the codec into ram and initialize it - keep it if it's ready */ | 1346 | /* Get the codec into ram and initialize it - keep it if it's ready */ |
@@ -1436,7 +1465,7 @@ static bool audio_start_codec(bool auto_skip) | |||
1436 | #ifdef HAVE_TAGCACHE | 1465 | #ifdef HAVE_TAGCACHE |
1437 | bool autoresume_enable = global_settings.autoresume_enable; | 1466 | bool autoresume_enable = global_settings.autoresume_enable; |
1438 | 1467 | ||
1439 | if (autoresume_enable && !cur_id3->offset) | 1468 | if (autoresume_enable && !(cur_id3->elapsed || cur_id3->offset)) |
1440 | { | 1469 | { |
1441 | /* Resume all manually selected tracks */ | 1470 | /* Resume all manually selected tracks */ |
1442 | bool resume = !auto_skip; | 1471 | bool resume = !auto_skip; |
@@ -1466,10 +1495,13 @@ static bool audio_start_codec(bool auto_skip) | |||
1466 | } | 1495 | } |
1467 | 1496 | ||
1468 | if (!resume) | 1497 | if (!resume) |
1498 | { | ||
1499 | cur_id3->elapsed = 0; | ||
1469 | cur_id3->offset = 0; | 1500 | cur_id3->offset = 0; |
1501 | } | ||
1470 | 1502 | ||
1471 | logf("%s: Set offset for %s to %lX\n", __func__, | 1503 | logf("%s: Set resume for %s to %lu %lX", __func__, |
1472 | cur_id3->title, cur_id3->offset); | 1504 | cur_id3->title, cur_id3->elapsed, cur_id3->offset); |
1473 | } | 1505 | } |
1474 | #endif /* HAVE_TAGCACHE */ | 1506 | #endif /* HAVE_TAGCACHE */ |
1475 | 1507 | ||
@@ -1481,7 +1513,8 @@ static bool audio_start_codec(bool auto_skip) | |||
1481 | and back again will cause accumulation of silent rewinds - that's not | 1513 | and back again will cause accumulation of silent rewinds - that's not |
1482 | our job to track directly nor could it be in any reasonable way | 1514 | our job to track directly nor could it be in any reasonable way |
1483 | */ | 1515 | */ |
1484 | cur_id3->offset = resume_rewind_adjusted_offset(cur_id3); | 1516 | resume_rewind_adjust_progress(cur_id3, &cur_id3->elapsed, |
1517 | &cur_id3->offset); | ||
1485 | 1518 | ||
1486 | /* Update the codec API with the metadata and track info */ | 1519 | /* Update the codec API with the metadata and track info */ |
1487 | id3_write(CODEC_ID3, cur_id3); | 1520 | id3_write(CODEC_ID3, cur_id3); |
@@ -1494,7 +1527,7 @@ static bool audio_start_codec(bool auto_skip) | |||
1494 | codec_go(); | 1527 | codec_go(); |
1495 | 1528 | ||
1496 | #ifdef HAVE_TAGCACHE | 1529 | #ifdef HAVE_TAGCACHE |
1497 | if (!autoresume_enable || cur_id3->offset) | 1530 | if (!autoresume_enable || cur_id3->elapsed || cur_id3->offset) |
1498 | #endif | 1531 | #endif |
1499 | { | 1532 | { |
1500 | /* Send the "buffer" event now */ | 1533 | /* Send the "buffer" event now */ |
@@ -1923,7 +1956,9 @@ static int audio_finish_load_track(struct track_info *info) | |||
1923 | 1956 | ||
1924 | /** Finally, load the audio **/ | 1957 | /** Finally, load the audio **/ |
1925 | size_t file_offset = 0; | 1958 | size_t file_offset = 0; |
1926 | track_id3->elapsed = 0; | 1959 | |
1960 | if (track_id3->elapsed > track_id3->length) | ||
1961 | track_id3->elapsed = 0; | ||
1927 | 1962 | ||
1928 | if (track_id3->offset >= info->filesize) | 1963 | if (track_id3->offset >= info->filesize) |
1929 | track_id3->offset = 0; | 1964 | track_id3->offset = 0; |
@@ -1933,7 +1968,11 @@ static int audio_finish_load_track(struct track_info *info) | |||
1933 | 1968 | ||
1934 | /* Adjust for resume rewind so we know what to buffer - starting the codec | 1969 | /* Adjust for resume rewind so we know what to buffer - starting the codec |
1935 | calls it again, so we don't save it (and they shouldn't accumulate) */ | 1970 | calls it again, so we don't save it (and they shouldn't accumulate) */ |
1936 | size_t offset = resume_rewind_adjusted_offset(track_id3); | 1971 | unsigned long elapsed, offset; |
1972 | resume_rewind_adjust_progress(track_id3, &elapsed, &offset); | ||
1973 | |||
1974 | logf("%s: Set resume for %s to %lu %lX", __func__, | ||
1975 | id3->title, elapsed, offset); | ||
1937 | 1976 | ||
1938 | enum data_type audiotype = rbcodec_format_is_atomic(track_id3->codectype) ? | 1977 | enum data_type audiotype = rbcodec_format_is_atomic(track_id3->codectype) ? |
1939 | TYPE_ATOMIC_AUDIO : TYPE_PACKET_AUDIO; | 1978 | TYPE_ATOMIC_AUDIO : TYPE_PACKET_AUDIO; |
@@ -2168,7 +2207,7 @@ static void audio_on_finish_load_track(int id3_hid) | |||
2168 | change otherwise */ | 2207 | change otherwise */ |
2169 | bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3)); | 2208 | bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3)); |
2170 | 2209 | ||
2171 | playing_id3_sync(info, -1); | 2210 | playing_id3_sync(info, -1, -1); |
2172 | 2211 | ||
2173 | if (!was_valid) | 2212 | if (!was_valid) |
2174 | { | 2213 | { |
@@ -2306,7 +2345,7 @@ static void audio_begin_track_change(enum pcm_track_change_type type, | |||
2306 | if (audio_start_codec(auto_skip)) | 2345 | if (audio_start_codec(auto_skip)) |
2307 | { | 2346 | { |
2308 | if (!auto_skip) | 2347 | if (!auto_skip) |
2309 | playing_id3_sync(info, -1); | 2348 | playing_id3_sync(info, -1, -1); |
2310 | return; | 2349 | return; |
2311 | } | 2350 | } |
2312 | 2351 | ||
@@ -2455,8 +2494,11 @@ static void audio_on_track_changed(void) | |||
2455 | /* Begin playback from an idle state, transition to a new playlist or | 2494 | /* Begin playback from an idle state, transition to a new playlist or |
2456 | invalidate the buffer and resume (if playing). | 2495 | invalidate the buffer and resume (if playing). |
2457 | (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */ | 2496 | (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */ |
2458 | static void audio_start_playback(size_t offset, unsigned int flags) | 2497 | static void audio_start_playback(const struct audio_resume_info *resume_info, |
2498 | unsigned int flags) | ||
2459 | { | 2499 | { |
2500 | struct audio_resume_info resume = | ||
2501 | *(resume_info ?: &(struct audio_resume_info){ 0, 0 } ); | ||
2460 | enum play_status old_status = play_status; | 2502 | enum play_status old_status = play_status; |
2461 | 2503 | ||
2462 | if (flags & AUDIO_START_NEWBUF) | 2504 | if (flags & AUDIO_START_NEWBUF) |
@@ -2469,7 +2511,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2469 | 2511 | ||
2470 | if (old_status != PLAY_STOPPED) | 2512 | if (old_status != PLAY_STOPPED) |
2471 | { | 2513 | { |
2472 | logf("%s(%lu): skipping", __func__, (unsigned long)offset); | 2514 | logf("%s(%lu, %lu): skipping", __func__, resume.elapsed, |
2515 | resume.offset); | ||
2473 | 2516 | ||
2474 | halt_decoding_track(true); | 2517 | halt_decoding_track(true); |
2475 | 2518 | ||
@@ -2481,7 +2524,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2481 | /* Clear out some stuff to resume the current track where it | 2524 | /* Clear out some stuff to resume the current track where it |
2482 | left off */ | 2525 | left off */ |
2483 | pcmbuf_play_stop(); | 2526 | pcmbuf_play_stop(); |
2484 | offset = id3_get(PLAYING_ID3)->offset; | 2527 | resume.elapsed = id3_get(PLAYING_ID3)->elapsed; |
2528 | resume.offset = id3_get(PLAYING_ID3)->offset; | ||
2485 | track_list_clear(TRACK_LIST_CLEAR_ALL); | 2529 | track_list_clear(TRACK_LIST_CLEAR_ALL); |
2486 | } | 2530 | } |
2487 | else | 2531 | else |
@@ -2505,7 +2549,8 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2505 | return; /* Must already be playing */ | 2549 | return; /* Must already be playing */ |
2506 | 2550 | ||
2507 | /* Cold playback start from a stopped state */ | 2551 | /* Cold playback start from a stopped state */ |
2508 | logf("%s(%lu): starting", __func__, offset); | 2552 | logf("%s(%lu, %lu): starting", __func__, resume.elapsed, |
2553 | resume.offset); | ||
2509 | 2554 | ||
2510 | /* Set audio parameters */ | 2555 | /* Set audio parameters */ |
2511 | #if INPUT_SRC_CAPS != 0 | 2556 | #if INPUT_SRC_CAPS != 0 |
@@ -2555,7 +2600,7 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2555 | if (trackstat >= LOAD_TRACK_OK) | 2600 | if (trackstat >= LOAD_TRACK_OK) |
2556 | { | 2601 | { |
2557 | /* This is the currently playing track - get metadata, stat */ | 2602 | /* This is the currently playing track - get metadata, stat */ |
2558 | playing_id3_sync(track_list_current(0), offset); | 2603 | playing_id3_sync(track_list_current(0), resume.elapsed, resume.offset); |
2559 | 2604 | ||
2560 | if (valid_mp3entry(id3_get(PLAYING_ID3))) | 2605 | if (valid_mp3entry(id3_get(PLAYING_ID3))) |
2561 | { | 2606 | { |
@@ -2892,7 +2937,9 @@ static void audio_on_ff_rewind(long time) | |||
2892 | 2937 | ||
2893 | if (!haltres) | 2938 | if (!haltres) |
2894 | { | 2939 | { |
2895 | /* If codec must be (re)started, reset the offset */ | 2940 | /* If codec must be (re)started, reset the resume info so that |
2941 | it doesn't execute resume procedures */ | ||
2942 | ci_id3->elapsed = 0; | ||
2896 | ci_id3->offset = 0; | 2943 | ci_id3->offset = 0; |
2897 | } | 2944 | } |
2898 | 2945 | ||
@@ -2970,7 +3017,7 @@ static void audio_on_audio_flush(void) | |||
2970 | not possible so a restart is required in order to continue the | 3017 | not possible so a restart is required in order to continue the |
2971 | currently playing track without the now invalid future track | 3018 | currently playing track without the now invalid future track |
2972 | playing */ | 3019 | playing */ |
2973 | audio_start_playback(0, AUDIO_START_RESTART); | 3020 | audio_start_playback(NULL, AUDIO_START_RESTART); |
2974 | break; | 3021 | break; |
2975 | 3022 | ||
2976 | default: /* Nothing else is a state */ | 3023 | default: /* Nothing else is a state */ |
@@ -3008,7 +3055,7 @@ void audio_playback_handler(struct queue_event *ev) | |||
3008 | /** Control messages **/ | 3055 | /** Control messages **/ |
3009 | case Q_AUDIO_PLAY: | 3056 | case Q_AUDIO_PLAY: |
3010 | LOGFQUEUE("playback < Q_AUDIO_PLAY"); | 3057 | LOGFQUEUE("playback < Q_AUDIO_PLAY"); |
3011 | audio_start_playback(ev->data, 0); | 3058 | audio_start_playback((struct audio_resume_info *)ev->data, 0); |
3012 | break; | 3059 | break; |
3013 | 3060 | ||
3014 | #ifdef HAVE_RECORDING | 3061 | #ifdef HAVE_RECORDING |
@@ -3082,7 +3129,7 @@ void audio_playback_handler(struct queue_event *ev) | |||
3082 | case Q_AUDIO_REMAKE_AUDIO_BUFFER: | 3129 | case Q_AUDIO_REMAKE_AUDIO_BUFFER: |
3083 | /* buffer needs to be reinitialized */ | 3130 | /* buffer needs to be reinitialized */ |
3084 | LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); | 3131 | LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); |
3085 | audio_start_playback(0, AUDIO_START_RESTART | AUDIO_START_NEWBUF); | 3132 | audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF); |
3086 | if (play_status == PLAY_STOPPED) | 3133 | if (play_status == PLAY_STOPPED) |
3087 | return; /* just need to change buffer state */ | 3134 | return; /* just need to change buffer state */ |
3088 | break; | 3135 | break; |
@@ -3368,8 +3415,8 @@ struct mp3entry * audio_next_track(void) | |||
3368 | return id3; | 3415 | return id3; |
3369 | } | 3416 | } |
3370 | 3417 | ||
3371 | /* Start playback at the specified offset */ | 3418 | /* Start playback at the specified elapsed time or offset */ |
3372 | void audio_play(long offset) | 3419 | void audio_play(unsigned long elapsed, unsigned long offset) |
3373 | { | 3420 | { |
3374 | logf("audio_play"); | 3421 | logf("audio_play"); |
3375 | 3422 | ||
@@ -3379,8 +3426,9 @@ void audio_play(long offset) | |||
3379 | talk_force_shutup(); | 3426 | talk_force_shutup(); |
3380 | #endif | 3427 | #endif |
3381 | 3428 | ||
3382 | LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset); | 3429 | LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %lu %lX", elapsed, offset); |
3383 | audio_queue_send(Q_AUDIO_PLAY, offset); | 3430 | audio_queue_send(Q_AUDIO_PLAY, |
3431 | (intptr_t)&(struct audio_resume_info){ elapsed, offset }); | ||
3384 | } | 3432 | } |
3385 | 3433 | ||
3386 | /* Stop playback if playing */ | 3434 | /* Stop playback if playing */ |
@@ -3582,11 +3630,10 @@ void playback_release_aa_slot(int slot) | |||
3582 | } | 3630 | } |
3583 | #endif /* HAVE_ALBUMART */ | 3631 | #endif /* HAVE_ALBUMART */ |
3584 | 3632 | ||
3585 | /* Would normally calculate byte offset from an elapsed time but is not | 3633 | /* Return file byte offset */ |
3586 | used on SWCODEC */ | ||
3587 | int audio_get_file_pos(void) | 3634 | int audio_get_file_pos(void) |
3588 | { | 3635 | { |
3589 | return 0; | 3636 | return id3_get(PLAYING_ID3)->offset; |
3590 | } | 3637 | } |
3591 | 3638 | ||
3592 | /* Return total file buffer length after accounting for the talk buf */ | 3639 | /* Return total file buffer length after accounting for the talk buf */ |