summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Gordon <rockbox@jdgordon.info>2009-04-06 00:39:43 +0000
committerJonathan Gordon <rockbox@jdgordon.info>2009-04-06 00:39:43 +0000
commit843c7efaf8c953fc3bec40a7da0be3a5da9950df (patch)
treecb27e411394f716d26193433c66132072730ea70
parent9188f0ffd7ce97101a5b2d697cc43072cd63b502 (diff)
downloadrockbox-843c7efaf8c953fc3bec40a7da0be3a5da9950df.tar.gz
rockbox-843c7efaf8c953fc3bec40a7da0be3a5da9950df.zip
FS9795 - some playback cleanup.
* Use events to notify things when the track has changed instead of the nasty has_track_changed() * Event for when the mp3entry for the next track is avilable (which allows alot more tags to be static which means less redrawing in the WPS) * virtually guarentee that the mp3entry sturct returned by audio_current/next_track() is going to be valid for the duration of the current track. The only time it wont be now is during the time between the codec finishing the previous track and the next track actually starting (~2s), but this is not an issue as long as it is called again when the TRACK_CHANGED event happens (or just use the pointer that gives) It is still possible to confuse the WPS with the next tracks id3 info being displayed but this should fix itself up faster than it used to (and be harder to do) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20633 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/appevents.h1
-rw-r--r--apps/gui/gwps-common.c39
-rw-r--r--apps/gui/gwps.c51
-rw-r--r--apps/gui/gwps.h1
-rw-r--r--apps/gui/wps_parser.c44
-rw-r--r--apps/iap.c6
-rw-r--r--apps/mpeg.c5
-rw-r--r--apps/playback.c210
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h5
-rw-r--r--firmware/export/audio.h1
-rw-r--r--firmware/export/iap.h2
12 files changed, 190 insertions, 176 deletions
diff --git a/apps/appevents.h b/apps/appevents.h
index 8cbc301ed7..e3c4a92ff8 100644
--- a/apps/appevents.h
+++ b/apps/appevents.h
@@ -34,6 +34,7 @@ enum {
34 PLAYBACK_EVENT_TRACK_BUFFER = (EVENT_CLASS_PLAYBACK|1), 34 PLAYBACK_EVENT_TRACK_BUFFER = (EVENT_CLASS_PLAYBACK|1),
35 PLAYBACK_EVENT_TRACK_FINISH, 35 PLAYBACK_EVENT_TRACK_FINISH,
36 PLAYBACK_EVENT_TRACK_CHANGE, 36 PLAYBACK_EVENT_TRACK_CHANGE,
37 PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
37}; 38};
38 39
39/** Buffering events **/ 40/** Buffering events **/
diff --git a/apps/gui/gwps-common.c b/apps/gui/gwps-common.c
index f32b002f69..189fc6fa31 100644
--- a/apps/gui/gwps-common.c
+++ b/apps/gui/gwps-common.c
@@ -348,33 +348,8 @@ bool gui_wps_display(struct gui_wps *gwps)
348 348
349bool gui_wps_update(struct gui_wps *gwps) 349bool gui_wps_update(struct gui_wps *gwps)
350{ 350{
351 bool track_changed = audio_has_changed_track();
352 struct mp3entry *id3 = gwps->state->id3; 351 struct mp3entry *id3 = gwps->state->id3;
353 352 bool retval;
354 gwps->state->nid3 = audio_next_track();
355 if (track_changed)
356 {
357 gwps->state->id3 = id3 = audio_current_track();
358
359 if (cuesheet_is_enabled() && id3->cuesheet_type
360 && strcmp(id3->path, curr_cue->audio_filename))
361 {
362 /* the current cuesheet isn't the right one any more */
363 /* We need to parse the new cuesheet */
364
365 char cuepath[MAX_PATH];
366
367 if (look_for_cuesheet_file(id3->path, cuepath) &&
368 parse_cuesheet(cuepath, curr_cue))
369 {
370 id3->cuesheet_type = 1;
371 strcpy(curr_cue->audio_filename, id3->path);
372 }
373
374 cue_spoof_id3(curr_cue, id3);
375 }
376 }
377
378 if (cuesheet_is_enabled() && id3->cuesheet_type 353 if (cuesheet_is_enabled() && id3->cuesheet_type
379 && (id3->elapsed < curr_cue->curr_track->offset 354 && (id3->elapsed < curr_cue->curr_track->offset
380 || (curr_cue->curr_track_idx < curr_cue->track_count - 1 355 || (curr_cue->curr_track_idx < curr_cue->track_count - 1
@@ -382,17 +357,15 @@ bool gui_wps_update(struct gui_wps *gwps)
382 { 357 {
383 /* We've changed tracks within the cuesheet : 358 /* We've changed tracks within the cuesheet :
384 we need to update the ID3 info and refresh the WPS */ 359 we need to update the ID3 info and refresh the WPS */
385 360 gwps->state->do_full_update = true;
386 track_changed = true;
387 cue_find_current_track(curr_cue, id3->elapsed); 361 cue_find_current_track(curr_cue, id3->elapsed);
388 cue_spoof_id3(curr_cue, id3); 362 cue_spoof_id3(curr_cue, id3);
389 } 363 }
390 364
391 if (track_changed) 365 retval = gui_wps_redraw(gwps, 0,
392 gwps->display->stop_scroll(); 366 gwps->state->do_full_update ?
393 367 WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC);
394 return gui_wps_redraw(gwps, 0, 368 return retval;
395 track_changed ? WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC);
396} 369}
397 370
398 371
diff --git a/apps/gui/gwps.c b/apps/gui/gwps.c
index 32a27212a4..5474b302f0 100644
--- a/apps/gui/gwps.c
+++ b/apps/gui/gwps.c
@@ -78,6 +78,8 @@ static struct wps_data wps_datas[NB_SCREENS];
78 78
79/* initial setup of wps_data */ 79/* initial setup of wps_data */
80static void wps_state_init(void); 80static void wps_state_init(void);
81static void track_changed_callback(void *param);
82static void nextid3available_callback(void* param);
81 83
82static void change_dir(int direction) 84static void change_dir(int direction)
83{ 85{
@@ -246,7 +248,7 @@ long gui_wps_show(void)
246 long restoretimer = RESTORE_WPS_INSTANTLY; /* timer to delay screen redraw temporarily */ 248 long restoretimer = RESTORE_WPS_INSTANTLY; /* timer to delay screen redraw temporarily */
247 bool exit = false; 249 bool exit = false;
248 bool bookmark = false; 250 bool bookmark = false;
249 bool update_track = false; 251 bool update_track = false, partial_update = false;
250 int i; 252 int i;
251 long last_left = 0, last_right = 0; 253 long last_left = 0, last_right = 0;
252 wps_state_init(); 254 wps_state_init();
@@ -651,7 +653,7 @@ long gui_wps_show(void)
651 restore = true; 653 restore = true;
652 break; 654 break;
653 case ACTION_NONE: /* Timeout */ 655 case ACTION_NONE: /* Timeout */
654 update_track = true; 656 partial_update = true;
655 ffwd_rew(button); /* hopefully fix the ffw/rwd bug */ 657 ffwd_rew(button); /* hopefully fix the ffw/rwd bug */
656 break; 658 break;
657#ifdef HAVE_RECORDING 659#ifdef HAVE_RECORDING
@@ -671,13 +673,21 @@ long gui_wps_show(void)
671 break; 673 break;
672 } 674 }
673 675
674 if (update_track) 676 if (wps_state.do_full_update || partial_update || update_track)
675 { 677 {
678 if (update_track)
679 {
680 wps_state.do_full_update = true;
681 wps_state.id3 = audio_current_track();
682 wps_state.nid3 = audio_next_track();
683 }
676 FOR_NB_SCREENS(i) 684 FOR_NB_SCREENS(i)
677 { 685 {
678 gui_wps_update(&gui_wps[i]); 686 gui_wps_update(&gui_wps[i]);
679 } 687 }
688 wps_state.do_full_update = false;
680 update_track = false; 689 update_track = false;
690 partial_update = false;
681 } 691 }
682 692
683 if (restore && wps_state.id3 && 693 if (restore && wps_state.id3 &&
@@ -723,7 +733,36 @@ long gui_wps_show(void)
723 return GO_TO_ROOT; /* unreachable - just to reduce compiler warnings */ 733 return GO_TO_ROOT; /* unreachable - just to reduce compiler warnings */
724} 734}
725 735
726/* needs checking if needed end*/ 736/* this is called from the playback thread so NO DRAWING! */
737static void track_changed_callback(void *param)
738{
739 wps_state.id3 = (struct mp3entry*)param;
740 wps_state.nid3 = audio_next_track();
741
742 if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type
743 && strcmp(wps_state.id3->path, curr_cue->audio_filename))
744 {
745 /* the current cuesheet isn't the right one any more */
746 /* We need to parse the new cuesheet */
747 char cuepath[MAX_PATH];
748
749 if (look_for_cuesheet_file(wps_state.id3->path, cuepath) &&
750 parse_cuesheet(cuepath, curr_cue))
751 {
752 wps_state.id3->cuesheet_type = 1;
753 strcpy(curr_cue->audio_filename, wps_state.id3->path);
754 }
755
756 cue_spoof_id3(curr_cue, wps_state.id3);
757 }
758 wps_state.do_full_update = true;
759}
760static void nextid3available_callback(void* param)
761{
762 (void)param;
763 wps_state.nid3 = audio_next_track();
764 wps_state.do_full_update = true;
765}
727 766
728/* wps_state */ 767/* wps_state */
729 768
@@ -733,6 +772,10 @@ static void wps_state_init(void)
733 wps_state.paused = false; 772 wps_state.paused = false;
734 wps_state.id3 = NULL; 773 wps_state.id3 = NULL;
735 wps_state.nid3 = NULL; 774 wps_state.nid3 = NULL;
775 wps_state.do_full_update = true;
776 /* add the WPS track event callbacks */
777 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback);
778 add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, nextid3available_callback);
736} 779}
737 780
738/* wps_state end*/ 781/* wps_state end*/
diff --git a/apps/gui/gwps.h b/apps/gui/gwps.h
index 7888c3944c..1042e1a795 100644
--- a/apps/gui/gwps.h
+++ b/apps/gui/gwps.h
@@ -478,6 +478,7 @@ struct wps_state
478 bool wps_time_countup; 478 bool wps_time_countup;
479 struct mp3entry* id3; 479 struct mp3entry* id3;
480 struct mp3entry* nid3; 480 struct mp3entry* nid3;
481 bool do_full_update;
481}; 482};
482 483
483 484
diff --git a/apps/gui/wps_parser.c b/apps/gui/wps_parser.c
index ba2e2173f1..390df56cbb 100644
--- a/apps/gui/wps_parser.c
+++ b/apps/gui/wps_parser.c
@@ -215,16 +215,16 @@ static const struct wps_tag all_tags[] = {
215 parse_dir_level }, 215 parse_dir_level },
216 216
217 /* next file */ 217 /* next file */
218 { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_DYNAMIC, NULL }, 218 { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_STATIC, NULL },
219 { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_DYNAMIC, NULL }, 219 { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_STATIC, NULL },
220 { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_DYNAMIC, NULL }, 220 { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_STATIC, NULL },
221 { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_DYNAMIC, NULL }, 221 { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_STATIC, NULL },
222 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_DYNAMIC, NULL }, 222 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_STATIC, NULL },
223 { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_DYNAMIC, NULL }, 223 { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_STATIC, NULL },
224 { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_DYNAMIC, NULL }, 224 { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_STATIC, NULL },
225 { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_DYNAMIC, NULL }, 225 { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_STATIC, NULL },
226 { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_DYNAMIC, NULL }, 226 { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_STATIC, NULL },
227 { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_DYNAMIC, 227 { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_STATIC,
228 parse_dir_level }, 228 parse_dir_level },
229 229
230 /* current metadata */ 230 /* current metadata */
@@ -242,18 +242,18 @@ static const struct wps_tag all_tags[] = {
242 { WPS_TOKEN_METADATA_COMMENT, "iC", WPS_REFRESH_STATIC, NULL }, 242 { WPS_TOKEN_METADATA_COMMENT, "iC", WPS_REFRESH_STATIC, NULL },
243 243
244 /* next metadata */ 244 /* next metadata */
245 { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_DYNAMIC, NULL }, 245 { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_STATIC, NULL },
246 { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_DYNAMIC, NULL }, 246 { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_STATIC, NULL },
247 { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_DYNAMIC, NULL }, 247 { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_STATIC, NULL },
248 { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_DYNAMIC, NULL }, 248 { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_STATIC, NULL },
249 { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_DYNAMIC, NULL }, 249 { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_STATIC, NULL },
250 { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_DYNAMIC, NULL }, 250 { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_STATIC, NULL },
251 { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_DYNAMIC, NULL }, 251 { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_STATIC, NULL },
252 { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_DYNAMIC, NULL }, 252 { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_STATIC, NULL },
253 { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_DYNAMIC, NULL }, 253 { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_STATIC, NULL },
254 { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_DYNAMIC, NULL }, 254 { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_STATIC, NULL },
255 { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_DYNAMIC, NULL }, 255 { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_STATIC, NULL },
256 { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_DYNAMIC, NULL }, 256 { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_STATIC, NULL },
257 257
258#if (CONFIG_CODEC != MAS3507D) 258#if (CONFIG_CODEC != MAS3507D)
259 { WPS_TOKEN_SOUND_PITCH, "Sp", WPS_REFRESH_DYNAMIC, NULL }, 259 { WPS_TOKEN_SOUND_PITCH, "Sp", WPS_REFRESH_DYNAMIC, NULL },
diff --git a/apps/iap.c b/apps/iap.c
index dd29563b1e..4d0c473800 100644
--- a/apps/iap.c
+++ b/apps/iap.c
@@ -29,6 +29,7 @@
29#include "system.h" 29#include "system.h"
30#include "kernel.h" 30#include "kernel.h"
31#include "serial.h" 31#include "serial.h"
32#include "appevents.h"
32 33
33#include "playlist.h" 34#include "playlist.h"
34#include "playback.h" 35#include "playback.h"
@@ -80,6 +81,7 @@ void iap_setup(int ratenum)
80 iap_setupflag = true; 81 iap_setupflag = true;
81 iap_remotebtn = BUTTON_NONE; 82 iap_remotebtn = BUTTON_NONE;
82 tick_add_task(iap_task); 83 tick_add_task(iap_task);
84 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed);
83} 85}
84 86
85void iap_bitrate_set(int ratenum) 87void iap_bitrate_set(int ratenum)
@@ -175,8 +177,10 @@ int iap_getc(unsigned char x)
175 return newpkt; 177 return newpkt;
176} 178}
177 179
178void iap_track_changed(void) 180/* called by playback when the next track starts */
181void iap_track_changed(void *ignored)
179{ 182{
183 (void)ignored;
180 iap_changedctr = 1; 184 iap_changedctr = 1;
181} 185}
182 186
diff --git a/apps/mpeg.c b/apps/mpeg.c
index cde72ab54f..5ebf58fcf0 100644
--- a/apps/mpeg.c
+++ b/apps/mpeg.c
@@ -852,6 +852,7 @@ static void transfer_end(unsigned char** ppbuf, size_t* psize)
852static struct trackdata *add_track_to_tag_list(const char *filename) 852static struct trackdata *add_track_to_tag_list(const char *filename)
853{ 853{
854 struct trackdata *track; 854 struct trackdata *track;
855 bool send_nid3_event;
855 856
856 if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES) 857 if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES)
857 { 858 {
@@ -882,7 +883,11 @@ static struct trackdata *add_track_to_tag_list(const char *filename)
882 if (cuesheet_callback(filename)) 883 if (cuesheet_callback(filename))
883 track->id3.cuesheet_type = 1; 884 track->id3.cuesheet_type = 1;
884 885
886 /* if this track is the next track then let the UI know it can get it */
887 send_nid3_event = (track_write_idx == track_read_idx + 1);
885 track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; 888 track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK;
889 if (send_nid3_event)
890 send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL);
886 debug_tags(); 891 debug_tags();
887 return track; 892 return track;
888} 893}
diff --git a/apps/playback.c b/apps/playback.c
index 11f76d4db8..3709b407fa 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -201,14 +201,15 @@ size_t filebuflen = 0; /* Size of buffer (A/C-) */
201/* Possible arrangements of the buffer */ 201/* Possible arrangements of the buffer */
202static int buffer_state = AUDIOBUF_STATE_TRASHED; /* Buffer state */ 202static int buffer_state = AUDIOBUF_STATE_TRASHED; /* Buffer state */
203 203
204/* Used to keep the WPS up-to-date during track transtition */ 204/* These are used to store the current and next (or prev if the current is the last)
205static struct mp3entry prevtrack_id3; 205 * mp3entry's in a round-robin system. This guarentees that the pointer returned
206 206 * by audio_current/next_track will be valid for the full duration of the
207/* Used to provide the codec with a pointer */ 207 * currently playing track */
208static struct mp3entry curtrack_id3; 208static struct mp3entry mp3entry_buf[2];
209 209static struct mp3entry *thistrack_id3, /* the currently playing track */
210/* Used to make next track info available while playing last track on buffer */ 210 *othertrack_id3; /* prev track during track-change-transition, or end of playlist,
211static struct mp3entry lasttrack_id3; 211 * next track otherwise */
212static struct mp3entry unbuffered_id3; /* the id3 for the first unbuffered track */
212 213
213/* Track info structure about songs in the file buffer (A/C-) */ 214/* Track info structure about songs in the file buffer (A/C-) */
214struct track_info { 215struct track_info {
@@ -232,10 +233,6 @@ static int track_widx = 0; /* Track being buffered (A) */
232static struct track_info *prev_ti = NULL; /* Pointer to the previously played 233static struct track_info *prev_ti = NULL; /* Pointer to the previously played
233 track */ 234 track */
234 235
235/* Set by the audio thread when the current track information has updated
236 * and the WPS may need to update its cached information */
237static bool track_changed = false;
238
239/* Information used only for filling the buffer */ 236/* Information used only for filling the buffer */
240/* Playlist steps from playing track to next track to be buffered (A) */ 237/* Playlist steps from playing track to next track to be buffered (A) */
241static int last_peek_offset = 0; 238static int last_peek_offset = 0;
@@ -567,24 +564,25 @@ struct mp3entry* audio_current_track(void)
567 564
568 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK; 565 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK;
569 566
570 if (cur_idx == track_ridx && *curtrack_id3.path) 567 if (cur_idx == track_ridx && *thistrack_id3->path)
571 { 568 {
572 /* The usual case */ 569 /* The usual case */
573 return &curtrack_id3; 570 return thistrack_id3;
574 } 571 }
575 else if (automatic_skip && offset == -1 && *prevtrack_id3.path) 572 else if (automatic_skip && offset == -1 && *othertrack_id3->path)
576 { 573 {
577 /* We're in a track transition. The codec has moved on to the nex track, 574 /* We're in a track transition. The codec has moved on to the next track,
578 but the audio being played is still the same (now previous) track. 575 but the audio being played is still the same (now previous) track.
579 prevtrack_id3.elapsed is being updated in an ISR by 576 othertrack_id3.elapsed is being updated in an ISR by
580 codec_pcmbuf_position_callback */ 577 codec_pcmbuf_position_callback */
581 return &prevtrack_id3; 578 return othertrack_id3;
582 } 579 }
583 else if (tracks[cur_idx].id3_hid >= 0) 580 else if (tracks[cur_idx].id3_hid >= 0)
584 { 581 {
585 /* Get the ID3 metadata from the main buffer */ 582 /* The current track's info has been buffered but not read yet, so get it */
586 struct mp3entry *ret = bufgetid3(tracks[cur_idx].id3_hid); 583 if (bufread(tracks[cur_idx].id3_hid, sizeof(struct mp3entry), &temp_id3)
587 if (ret) return ret; 584 == sizeof(struct mp3entry))
585 return &temp_id3;
588 } 586 }
589 587
590 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info 588 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info
@@ -620,42 +618,34 @@ struct mp3entry* audio_next_track(void)
620 if (!audio_have_tracks()) 618 if (!audio_have_tracks())
621 return NULL; 619 return NULL;
622 620
623 if (wps_offset == -1 && *prevtrack_id3.path) 621 if (wps_offset == -1 && *thistrack_id3->path)
624 { 622 {
625 /* We're in a track transition. The next track for the WPS is the one 623 /* We're in a track transition. The next track for the WPS is the one
626 currently being decoded. */ 624 currently being decoded. */
627 return &curtrack_id3; 625 return thistrack_id3;
628 } 626 }
629 627
630 next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK; 628 next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK;
631 629
632 if (tracks[next_idx].id3_hid >= 0) 630 if (tracks[next_idx].id3_hid >= 0)
633 return bufgetid3(tracks[next_idx].id3_hid); 631 {
632 if (bufread(tracks[next_idx].id3_hid, sizeof(struct mp3entry), othertrack_id3)
633 == sizeof(struct mp3entry))
634 return othertrack_id3;
635 else
636 return NULL;
637 }
634 638
635 if (next_idx == track_widx) 639 if (next_idx == track_widx)
636 { 640 {
637 /* The next track hasn't been buffered yet, so we return the static 641 /* The next track hasn't been buffered yet, so we return the static
638 version of its metadata. */ 642 version of its metadata. */
639 return &lasttrack_id3; 643 return &unbuffered_id3;
640 } 644 }
641 645
642 return NULL; 646 return NULL;
643} 647}
644 648
645bool audio_has_changed_track(void)
646{
647 if (track_changed)
648 {
649#ifdef IPOD_ACCESSORY_PROTOCOL
650 iap_track_changed();
651#endif
652 track_changed = false;
653 return true;
654 }
655
656 return false;
657}
658
659void audio_play(long offset) 649void audio_play(long offset)
660{ 650{
661 logf("audio_play"); 651 logf("audio_play");
@@ -705,7 +695,6 @@ void audio_skip(int direction)
705 queue_post(&audio_queue, Q_AUDIO_SKIP, direction); 695 queue_post(&audio_queue, Q_AUDIO_SKIP, direction);
706 /* Update wps while our message travels inside deep playback queues. */ 696 /* Update wps while our message travels inside deep playback queues. */
707 wps_offset += direction; 697 wps_offset += direction;
708 track_changed = true;
709 } 698 }
710 else 699 else
711 { 700 {
@@ -823,7 +812,7 @@ void audio_set_crossfade(int enable)
823 if (was_playing) 812 if (was_playing)
824 { 813 {
825 /* Store the track resume position */ 814 /* Store the track resume position */
826 offset = curtrack_id3.offset; 815 offset = thistrack_id3->offset;
827 } 816 }
828 817
829 /* Blast it - audio buffer will have to be setup again next time 818 /* Blast it - audio buffer will have to be setup again next time
@@ -963,15 +952,15 @@ static void codec_pcmbuf_position_callback(size_t size)
963{ 952{
964 /* This is called from an ISR, so be quick */ 953 /* This is called from an ISR, so be quick */
965 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + 954 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
966 prevtrack_id3.elapsed; 955 othertrack_id3->elapsed;
967 956
968 if (time >= prevtrack_id3.length) 957 if (time >= othertrack_id3->length)
969 { 958 {
970 pcmbuf_set_position_callback(NULL); 959 pcmbuf_set_position_callback(NULL);
971 prevtrack_id3.elapsed = prevtrack_id3.length; 960 othertrack_id3->elapsed = othertrack_id3->length;
972 } 961 }
973 else 962 else
974 prevtrack_id3.elapsed = time; 963 othertrack_id3->elapsed = time;
975} 964}
976 965
977static void codec_set_elapsed_callback(unsigned int value) 966static void codec_set_elapsed_callback(unsigned int value)
@@ -986,11 +975,11 @@ static void codec_set_elapsed_callback(unsigned int value)
986 975
987 latency = pcmbuf_get_latency(); 976 latency = pcmbuf_get_latency();
988 if (value < latency) 977 if (value < latency)
989 curtrack_id3.elapsed = 0; 978 thistrack_id3->elapsed = 0;
990 else if (value - latency > curtrack_id3.elapsed || 979 else if (value - latency > thistrack_id3->elapsed ||
991 value - latency < curtrack_id3.elapsed - 2) 980 value - latency < thistrack_id3->elapsed - 2)
992 { 981 {
993 curtrack_id3.elapsed = value - latency; 982 thistrack_id3->elapsed = value - latency;
994 } 983 }
995} 984}
996 985
@@ -1001,11 +990,11 @@ static void codec_set_offset_callback(size_t value)
1001 if (ci.seek_time) 990 if (ci.seek_time)
1002 return; 991 return;
1003 992
1004 latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8; 993 latency = pcmbuf_get_latency() * thistrack_id3->bitrate / 8;
1005 if (value < latency) 994 if (value < latency)
1006 curtrack_id3.offset = 0; 995 thistrack_id3->offset = 0;
1007 else 996 else
1008 curtrack_id3.offset = value - latency; 997 thistrack_id3->offset = value - latency;
1009} 998}
1010 999
1011static void codec_advance_buffer_counters(size_t amount) 1000static void codec_advance_buffer_counters(size_t amount)
@@ -1197,7 +1186,7 @@ static bool codec_load_next_track(void)
1197{ 1186{
1198 intptr_t result = Q_CODEC_REQUEST_FAILED; 1187 intptr_t result = Q_CODEC_REQUEST_FAILED;
1199 1188
1200 prev_track_elapsed = curtrack_id3.elapsed; 1189 prev_track_elapsed = thistrack_id3->elapsed;
1201 1190
1202#ifdef AB_REPEAT_ENABLE 1191#ifdef AB_REPEAT_ENABLE
1203 ab_end_of_track_report(); 1192 ab_end_of_track_report();
@@ -1247,18 +1236,16 @@ static bool codec_request_next_track_callback(void)
1247 if (ci.stop_codec || !playing) 1236 if (ci.stop_codec || !playing)
1248 return false; 1237 return false;
1249 1238
1250 prev_codectype = get_codec_base_type(curtrack_id3.codectype); 1239 prev_codectype = get_codec_base_type(thistrack_id3->codectype);
1251
1252 if (!codec_load_next_track()) 1240 if (!codec_load_next_track())
1253 return false; 1241 return false;
1254 1242
1255 /* Seek to the beginning of the new track because if the struct 1243 /* Seek to the beginning of the new track because if the struct
1256 mp3entry was buffered, "elapsed" might not be zero (if the track has 1244 mp3entry was buffered, "elapsed" might not be zero (if the track has
1257 been played already but not unbuffered) */ 1245 been played already but not unbuffered) */
1258 codec_seek_buffer_callback(curtrack_id3.first_frame_offset); 1246 codec_seek_buffer_callback(thistrack_id3->first_frame_offset);
1259
1260 /* Check if the next codec is the same file. */ 1247 /* Check if the next codec is the same file. */
1261 if (prev_codectype == get_codec_base_type(curtrack_id3.codectype)) 1248 if (prev_codectype == get_codec_base_type(thistrack_id3->codectype))
1262 { 1249 {
1263 logf("New track loaded"); 1250 logf("New track loaded");
1264 codec_discard_codec_callback(); 1251 codec_discard_codec_callback();
@@ -1266,7 +1253,7 @@ static bool codec_request_next_track_callback(void)
1266 } 1253 }
1267 else 1254 else
1268 { 1255 {
1269 logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype); 1256 logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype);
1270 return false; 1257 return false;
1271 } 1258 }
1272} 1259}
@@ -1293,6 +1280,7 @@ static void codec_thread(void)
1293 audio_codec_loaded = true; 1280 audio_codec_loaded = true;
1294 ci.stop_codec = false; 1281 ci.stop_codec = false;
1295 status = codec_load_file((const char *)ev.data, &ci); 1282 status = codec_load_file((const char *)ev.data, &ci);
1283 LOGFQUEUE("codec_load_file %s %d\n", (const char *)ev.data, status);
1296 break; 1284 break;
1297 1285
1298 case Q_CODEC_LOAD: 1286 case Q_CODEC_LOAD:
@@ -1312,6 +1300,7 @@ static void codec_thread(void)
1312 audio_codec_loaded = true; 1300 audio_codec_loaded = true;
1313 ci.stop_codec = false; 1301 ci.stop_codec = false;
1314 status = codec_load_buf(CUR_TI->codec_hid, &ci); 1302 status = codec_load_buf(CUR_TI->codec_hid, &ci);
1303 LOGFQUEUE("codec_load_buf %d\n", status);
1315 break; 1304 break;
1316 1305
1317 case Q_CODEC_DO_CALLBACK: 1306 case Q_CODEC_DO_CALLBACK:
@@ -1362,7 +1351,7 @@ static void codec_thread(void)
1362 { 1351 {
1363 if (!ci.new_track) 1352 if (!ci.new_track)
1364 { 1353 {
1365 logf("Codec failure"); 1354 logf("Codec failure, %d %d", ci.new_track, status);
1366 splash(HZ*2, "Codec failure"); 1355 splash(HZ*2, "Codec failure");
1367 } 1356 }
1368 1357
@@ -1383,8 +1372,10 @@ static void codec_thread(void)
1383 * triggering the WPS exit */ 1372 * triggering the WPS exit */
1384 while(pcm_is_playing()) 1373 while(pcm_is_playing())
1385 { 1374 {
1386 curtrack_id3.elapsed = 1375 /* There has been one too many struct pointer swaps by now
1387 curtrack_id3.length - pcmbuf_get_latency(); 1376 * so even though it says othertrack_id3, its the correct one! */
1377 othertrack_id3->elapsed =
1378 othertrack_id3->length - pcmbuf_get_latency();
1388 sleep(1); 1379 sleep(1);
1389 } 1380 }
1390 1381
@@ -1405,7 +1396,7 @@ static void codec_thread(void)
1405 else 1396 else
1406 { 1397 {
1407 const char *codec_fn = 1398 const char *codec_fn =
1408 get_codec_filename(curtrack_id3.codectype); 1399 get_codec_filename(thistrack_id3->codectype);
1409 if (codec_fn) 1400 if (codec_fn)
1410 { 1401 {
1411 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); 1402 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
@@ -1481,10 +1472,14 @@ static void buffering_handle_finished_callback(int *data)
1481 1472
1482 if (*data == tracks[track_widx].id3_hid) 1473 if (*data == tracks[track_widx].id3_hid)
1483 { 1474 {
1475 int offset = ci.new_track + wps_offset;
1476 int next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK;
1484 /* The metadata handle for the last loaded track has been buffered. 1477 /* The metadata handle for the last loaded track has been buffered.
1485 We can ask the audio thread to load the rest of the track's data. */ 1478 We can ask the audio thread to load the rest of the track's data. */
1486 LOGFQUEUE("audio >| audio Q_AUDIO_FINISH_LOAD"); 1479 LOGFQUEUE("audio >| audio Q_AUDIO_FINISH_LOAD");
1487 queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0); 1480 queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0);
1481 if (tracks[next_idx].id3_hid == *data)
1482 send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL);
1488 } 1483 }
1489 else 1484 else
1490 { 1485 {
@@ -1534,15 +1529,15 @@ static void audio_update_trackinfo(void)
1534{ 1529{
1535 /* Load the curent track's metadata into curtrack_id3 */ 1530 /* Load the curent track's metadata into curtrack_id3 */
1536 if (CUR_TI->id3_hid >= 0) 1531 if (CUR_TI->id3_hid >= 0)
1537 copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid)); 1532 copy_mp3entry(thistrack_id3, bufgetid3(CUR_TI->id3_hid));
1538 1533
1539 /* Reset current position */ 1534 /* Reset current position */
1540 curtrack_id3.elapsed = 0; 1535 thistrack_id3->elapsed = 0;
1541 curtrack_id3.offset = 0; 1536 thistrack_id3->offset = 0;
1542 1537
1543 /* Update the codec API */ 1538 /* Update the codec API */
1544 ci.filesize = CUR_TI->filesize; 1539 ci.filesize = CUR_TI->filesize;
1545 ci.id3 = &curtrack_id3; 1540 ci.id3 = thistrack_id3;
1546 ci.curpos = 0; 1541 ci.curpos = 0;
1547 ci.taginfo_ready = &CUR_TI->taginfo_ready; 1542 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1548} 1543}
@@ -1608,7 +1603,7 @@ static bool audio_loadcodec(bool start_play)
1608 /* Load the codec directly from disk and save some memory. */ 1603 /* Load the codec directly from disk and save some memory. */
1609 track_ridx = track_widx; 1604 track_ridx = track_widx;
1610 ci.filesize = CUR_TI->filesize; 1605 ci.filesize = CUR_TI->filesize;
1611 ci.id3 = &curtrack_id3; 1606 ci.id3 = thistrack_id3;
1612 ci.taginfo_ready = &CUR_TI->taginfo_ready; 1607 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1613 ci.curpos = 0; 1608 ci.curpos = 0;
1614 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); 1609 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
@@ -1698,10 +1693,10 @@ static bool audio_load_track(size_t offset, bool start_play)
1698 if (!trackname) 1693 if (!trackname)
1699 { 1694 {
1700 logf("End-of-playlist"); 1695 logf("End-of-playlist");
1701 memset(&lasttrack_id3, 0, sizeof(struct mp3entry)); 1696 memset(&unbuffered_id3, 0, sizeof(struct mp3entry));
1702 filling = STATE_END_OF_PLAYLIST; 1697 filling = STATE_END_OF_PLAYLIST;
1703 1698
1704 if (curtrack_id3.length == 0 && curtrack_id3.filesize == 0) 1699 if (thistrack_id3->length == 0 && thistrack_id3->filesize == 0)
1705 { 1700 {
1706 /* Stop playback if no valid track was found. */ 1701 /* Stop playback if no valid track was found. */
1707 audio_stop_playback(); 1702 audio_stop_playback();
@@ -1720,7 +1715,6 @@ static bool audio_load_track(size_t offset, bool start_play)
1720 { 1715 {
1721 buf_set_watermark(filebuflen/2); 1716 buf_set_watermark(filebuflen/2);
1722 dsp_configure(ci.dsp, DSP_RESET, 0); 1717 dsp_configure(ci.dsp, DSP_RESET, 0);
1723 track_changed = true;
1724 playlist_update_resume_info(audio_current_track()); 1718 playlist_update_resume_info(audio_current_track());
1725 } 1719 }
1726 1720
@@ -1732,7 +1726,7 @@ static bool audio_load_track(size_t offset, bool start_play)
1732 if (tracks[track_widx].id3_hid < 0) 1726 if (tracks[track_widx].id3_hid < 0)
1733 { 1727 {
1734 /* Buffer is full. */ 1728 /* Buffer is full. */
1735 get_metadata(&lasttrack_id3, fd, trackname); 1729 get_metadata(&unbuffered_id3, fd, trackname);
1736 last_peek_offset--; 1730 last_peek_offset--;
1737 close(fd); 1731 close(fd);
1738 logf("buffer is full for now"); 1732 logf("buffer is full for now");
@@ -1744,13 +1738,18 @@ static bool audio_load_track(size_t offset, bool start_play)
1744 { 1738 {
1745 /* TODO: Superfluos buffering call? */ 1739 /* TODO: Superfluos buffering call? */
1746 buf_request_buffer_handle(tracks[track_widx].id3_hid); 1740 buf_request_buffer_handle(tracks[track_widx].id3_hid);
1747 copy_mp3entry(&curtrack_id3, bufgetid3(tracks[track_widx].id3_hid)); 1741 struct mp3entry *id3 = bufgetid3(tracks[track_widx].id3_hid);
1748 curtrack_id3.offset = offset; 1742 if (id3)
1743 {
1744 copy_mp3entry(thistrack_id3, id3);
1745 thistrack_id3->offset = offset;
1746 }
1747 else
1748 memset(thistrack_id3, 0, sizeof(struct mp3entry));
1749 } 1749 }
1750 1750
1751 if (start_play) 1751 if (start_play)
1752 { 1752 {
1753 track_changed = true;
1754 playlist_update_resume_info(audio_current_track()); 1753 playlist_update_resume_info(audio_current_track());
1755 } 1754 }
1756 } 1755 }
@@ -1780,7 +1779,7 @@ static void audio_finish_load_track(void)
1780 struct mp3entry *track_id3; 1779 struct mp3entry *track_id3;
1781 1780
1782 if (track_widx == track_ridx) 1781 if (track_widx == track_ridx)
1783 track_id3 = &curtrack_id3; 1782 track_id3 = thistrack_id3;
1784 else 1783 else
1785 track_id3 = bufgetid3(tracks[track_widx].id3_hid); 1784 track_id3 = bufgetid3(tracks[track_widx].id3_hid);
1786 1785
@@ -1935,8 +1934,6 @@ static void audio_finish_load_track(void)
1935 1934
1936static void audio_fill_file_buffer(bool start_play, size_t offset) 1935static void audio_fill_file_buffer(bool start_play, size_t offset)
1937{ 1936{
1938 bool had_next_track = audio_next_track() != NULL;
1939
1940 filling = STATE_FILLING; 1937 filling = STATE_FILLING;
1941 trigger_cpu_boost(); 1938 trigger_cpu_boost();
1942 1939
@@ -1959,9 +1956,6 @@ static void audio_fill_file_buffer(bool start_play, size_t offset)
1959 playlist_update_resume_info(audio_current_track()); 1956 playlist_update_resume_info(audio_current_track());
1960 1957
1961 audio_load_track(offset, start_play); 1958 audio_load_track(offset, start_play);
1962
1963 if (!had_next_track && audio_next_track())
1964 track_changed = true;
1965} 1959}
1966 1960
1967static void audio_rebuffer(void) 1961static void audio_rebuffer(void)
@@ -1982,7 +1976,7 @@ static void audio_rebuffer(void)
1982 ci.curpos = 0; 1976 ci.curpos = 0;
1983 1977
1984 if (!CUR_TI->taginfo_ready) 1978 if (!CUR_TI->taginfo_ready)
1985 memset(&curtrack_id3, 0, sizeof(struct mp3entry)); 1979 memset(thistrack_id3, 0, sizeof(struct mp3entry));
1986 1980
1987 audio_fill_file_buffer(false, 0); 1981 audio_fill_file_buffer(false, 0);
1988} 1982}
@@ -1995,9 +1989,16 @@ static int audio_check_new_track(void)
1995 int old_track_ridx = track_ridx; 1989 int old_track_ridx = track_ridx;
1996 int i, idx; 1990 int i, idx;
1997 bool forward; 1991 bool forward;
1992 struct mp3entry *temp = thistrack_id3;
1998 1993
1999 /* Now it's good time to send track finish events. */ 1994 /* Now it's good time to send track finish events. */
2000 send_event(PLAYBACK_EVENT_TRACK_FINISH, &curtrack_id3); 1995 send_event(PLAYBACK_EVENT_TRACK_FINISH, thistrack_id3);
1996 /* swap the mp3entry pointers */
1997 thistrack_id3 = othertrack_id3;
1998 othertrack_id3 = temp;
1999 ci.id3 = thistrack_id3;
2000 memset(thistrack_id3, 0, sizeof(struct mp3entry));
2001
2001 if (dir_skip) 2002 if (dir_skip)
2002 { 2003 {
2003 dir_skip = false; 2004 dir_skip = false;
@@ -2035,22 +2036,23 @@ static int audio_check_new_track(void)
2035 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED"); 2036 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2036 return Q_CODEC_REQUEST_FAILED; 2037 return Q_CODEC_REQUEST_FAILED;
2037 } 2038 }
2038 2039
2039 if (new_playlist) 2040 if (new_playlist)
2040 { 2041 {
2041 ci.new_track = 1; 2042 ci.new_track = 1;
2042 new_playlist = false; 2043 new_playlist = false;
2043 } 2044 }
2044 2045
2045 /* Save the track metadata to allow the WPS to display it 2046 /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
2046 while PCM finishes playing that track */ 2047 * 1) why are we doing this?
2047 copy_mp3entry(&prevtrack_id3, &curtrack_id3); 2048 * 2) thistrack_id3 has already been cleared anyway */
2048
2049 /* Update the main buffer copy of the track metadata with the one 2049 /* Update the main buffer copy of the track metadata with the one
2050 the codec has been using (for the unbuffer callbacks) */ 2050 the codec has been using (for the unbuffer callbacks) */
2051 if (CUR_TI->id3_hid >= 0) 2051 if (CUR_TI->id3_hid >= 0)
2052 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3); 2052 copy_mp3entry(bufgetid3(CUR_TI->id3_hid), thistrack_id3);
2053 2053 /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME */
2054
2055
2054 /* Save a pointer to the old track to allow later clearing */ 2056 /* Save a pointer to the old track to allow later clearing */
2055 prev_ti = CUR_TI; 2057 prev_ti = CUR_TI;
2056 2058
@@ -2079,7 +2081,6 @@ static int audio_check_new_track(void)
2079 if (automatic_skip) 2081 if (automatic_skip)
2080 { 2082 {
2081 wps_offset = -ci.new_track; 2083 wps_offset = -ci.new_track;
2082 track_changed = true;
2083 } 2084 }
2084 2085
2085 /* If it is not safe to even skip this many track entries */ 2086 /* If it is not safe to even skip this many track entries */
@@ -2185,7 +2186,7 @@ static void audio_stop_playback(void)
2185 2186
2186 /* TODO: Create auto bookmark too? */ 2187 /* TODO: Create auto bookmark too? */
2187 2188
2188 prev_track_elapsed = curtrack_id3.elapsed; 2189 prev_track_elapsed = othertrack_id3->elapsed;
2189 2190
2190 remove_event(BUFFER_EVENT_BUFFER_LOW, buffering_low_buffer_callback); 2191 remove_event(BUFFER_EVENT_BUFFER_LOW, buffering_low_buffer_callback);
2191 } 2192 }
@@ -2202,8 +2203,6 @@ static void audio_stop_playback(void)
2202 2203
2203 /* Close all tracks */ 2204 /* Close all tracks */
2204 audio_release_tracks(); 2205 audio_release_tracks();
2205
2206 memset(&curtrack_id3, 0, sizeof(struct mp3entry));
2207} 2206}
2208 2207
2209static void audio_play_start(size_t offset) 2208static void audio_play_start(size_t offset)
@@ -2219,8 +2218,6 @@ static void audio_play_start(size_t offset)
2219 paused = false; 2218 paused = false;
2220 audio_stop_codec_flush(); 2219 audio_stop_codec_flush();
2221 2220
2222 track_changed = true;
2223
2224 playing = true; 2221 playing = true;
2225 track_load_started = false; 2222 track_load_started = false;
2226 2223
@@ -2325,25 +2322,15 @@ static void audio_finalise_track_change(void)
2325 automatic_skip = false; 2322 automatic_skip = false;
2326 2323
2327 /* Invalidate prevtrack_id3 */ 2324 /* Invalidate prevtrack_id3 */
2328 prevtrack_id3.path[0] = 0; 2325 memset(othertrack_id3, 0, sizeof(struct mp3entry));
2329 2326
2330 if (prev_ti && prev_ti->audio_hid < 0) 2327 if (prev_ti && prev_ti->audio_hid < 0)
2331 { 2328 {
2332 /* No audio left so we clear all the track info. */ 2329 /* No audio left so we clear all the track info. */
2333 clear_track_info(prev_ti); 2330 clear_track_info(prev_ti);
2334 } 2331 }
2335
2336 if (prev_ti && prev_ti->id3_hid >= 0)
2337 {
2338 /* Reset the elapsed time to force the progressbar to be empty if
2339 the user skips back to this track */
2340 bufgetid3(prev_ti->id3_hid)->elapsed = 0;
2341 }
2342 } 2332 }
2343 2333 send_event(PLAYBACK_EVENT_TRACK_CHANGE, thistrack_id3);
2344 send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3);
2345
2346 track_changed = true;
2347 playlist_update_resume_info(audio_current_track()); 2334 playlist_update_resume_info(audio_current_track());
2348} 2335}
2349 2336
@@ -2588,6 +2575,9 @@ void audio_init(void)
2588 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP, 2575 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
2589 CODEC_IDX_AUDIO); 2576 CODEC_IDX_AUDIO);
2590 2577
2578 thistrack_id3 = &mp3entry_buf[0];
2579 othertrack_id3 = &mp3entry_buf[1];
2580
2591 /* initialize the buffer */ 2581 /* initialize the buffer */
2592 filebuf = audiobuf; 2582 filebuf = audiobuf;
2593 2583
diff --git a/apps/plugin.c b/apps/plugin.c
index 2126641572..17e9ac670b 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -463,7 +463,6 @@ static const struct plugin_api rockbox_api = {
463 audio_ff_rewind, 463 audio_ff_rewind,
464 audio_next_track, 464 audio_next_track,
465 audio_status, 465 audio_status,
466 audio_has_changed_track,
467 audio_current_track, 466 audio_current_track,
468 audio_flush_and_reload_tracks, 467 audio_flush_and_reload_tracks,
469 audio_get_file_pos, 468 audio_get_file_pos,
diff --git a/apps/plugin.h b/apps/plugin.h
index 8954373d23..fdcf3c2afa 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -128,12 +128,12 @@ void* plugin_get_buffer(size_t *buffer_size);
128#define PLUGIN_MAGIC 0x526F634B /* RocK */ 128#define PLUGIN_MAGIC 0x526F634B /* RocK */
129 129
130/* increase this every time the api struct changes */ 130/* increase this every time the api struct changes */
131#define PLUGIN_API_VERSION 146 131#define PLUGIN_API_VERSION 147
132 132
133/* update this to latest version if a change to the api struct breaks 133/* update this to latest version if a change to the api struct breaks
134 backwards compatibility (and please take the opportunity to sort in any 134 backwards compatibility (and please take the opportunity to sort in any
135 new function which are "waiting" at the end of the function table) */ 135 new function which are "waiting" at the end of the function table) */
136#define PLUGIN_MIN_API_VERSION 146 136#define PLUGIN_MIN_API_VERSION 147
137 137
138/* plugin return codes */ 138/* plugin return codes */
139enum plugin_status { 139enum plugin_status {
@@ -588,7 +588,6 @@ struct plugin_api {
588 void (*audio_ff_rewind)(long newtime); 588 void (*audio_ff_rewind)(long newtime);
589 struct mp3entry* (*audio_next_track)(void); 589 struct mp3entry* (*audio_next_track)(void);
590 int (*audio_status)(void); 590 int (*audio_status)(void);
591 bool (*audio_has_changed_track)(void);
592 struct mp3entry* (*audio_current_track)(void); 591 struct mp3entry* (*audio_current_track)(void);
593 void (*audio_flush_and_reload_tracks)(void); 592 void (*audio_flush_and_reload_tracks)(void);
594 int (*audio_get_file_pos)(void); 593 int (*audio_get_file_pos)(void);
diff --git a/firmware/export/audio.h b/firmware/export/audio.h
index b4a2c82200..6236c6d5d1 100644
--- a/firmware/export/audio.h
+++ b/firmware/export/audio.h
@@ -89,7 +89,6 @@ void audio_ff_rewind(long newtime);
89void audio_flush_and_reload_tracks(void); 89void audio_flush_and_reload_tracks(void);
90struct mp3entry* audio_current_track(void); 90struct mp3entry* audio_current_track(void);
91struct mp3entry* audio_next_track(void); 91struct mp3entry* audio_next_track(void);
92bool audio_has_changed_track(void);
93void audio_get_debugdata(struct audio_debug *dbgdata); 92void audio_get_debugdata(struct audio_debug *dbgdata);
94#ifdef HAVE_DISK_STORAGE 93#ifdef HAVE_DISK_STORAGE
95void audio_set_buffer_margin(int seconds); 94void audio_set_buffer_margin(int seconds);
diff --git a/firmware/export/iap.h b/firmware/export/iap.h
index 6c0b968ab0..d3afd6ba04 100644
--- a/firmware/export/iap.h
+++ b/firmware/export/iap.h
@@ -26,6 +26,6 @@ extern void iap_setup(int ratenum);
26extern void iap_bitrate_set(int ratenum); 26extern void iap_bitrate_set(int ratenum);
27extern void iap_periodic(void); 27extern void iap_periodic(void);
28extern void iap_handlepkt(void); 28extern void iap_handlepkt(void);
29extern void iap_track_changed(void); 29extern void iap_track_changed(void *ignored);
30 30
31#endif 31#endif