diff options
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 */ |