Index: apps/gui/gwps-common.c =================================================================== --- apps/gui/gwps-common.c (revision 19758) +++ apps/gui/gwps-common.c (working copy) @@ -424,48 +424,7 @@ bool update(struct gui_wps *gwps) { - bool track_changed = audio_has_changed_track(); bool retcode = false; - - gwps->state->nid3 = audio_next_track(); - if (track_changed) - { - gwps->display->stop_scroll(); - gwps->state->id3 = audio_current_track(); - - if (cuesheet_is_enabled() && gwps->state->id3->cuesheet_type - && strcmp(gwps->state->id3->path, curr_cue->audio_filename)) - { - /* the current cuesheet isn't the right one any more */ - - if (!strcmp(gwps->state->id3->path, temp_cue->audio_filename)) { - /* We have the new cuesheet in memory (temp_cue), - let's make it the current one ! */ - memcpy(curr_cue, temp_cue, sizeof(struct cuesheet)); - } - else { - /* We need to parse the new cuesheet */ - - char cuepath[MAX_PATH]; - - if (look_for_cuesheet_file(gwps->state->id3->path, cuepath) && - parse_cuesheet(cuepath, curr_cue)) - { - gwps->state->id3->cuesheet_type = 1; - strcpy(curr_cue->audio_filename, gwps->state->id3->path); - } - } - - cue_spoof_id3(curr_cue, gwps->state->id3); - } - - if (gui_wps_display()) - retcode = true; - else{ - gui_wps_refresh(gwps, 0, WPS_REFRESH_ALL); - } - } - if (gwps->state->id3) { if (cuesheet_is_enabled() && gwps->state->id3->cuesheet_type @@ -485,10 +444,20 @@ else gui_wps_refresh(gwps, 0, WPS_REFRESH_ALL); } - else + else if (wps_state.do_full_update) + { + gui_wps_refresh(gwps, 0, WPS_REFRESH_ALL); + wps_state.do_full_update = false; + } + else gui_wps_refresh(gwps, 0, WPS_REFRESH_NON_STATIC); } - + else if (wps_state.do_full_update) + { + gui_wps_refresh(gwps, 0, WPS_REFRESH_ALL); + wps_state.do_full_update = false; + } + gui_wps_statusbar_draw(gwps, false); return retcode; Index: apps/gui/gwps.c =================================================================== --- apps/gui/gwps.c (revision 19758) +++ apps/gui/gwps.c (working copy) @@ -664,6 +664,8 @@ if (update_track) { + wps_state.do_full_update = true; + wps_state.id3 = audio_current_track(); FOR_NB_SCREENS(i) { if(update(&gui_wps[i])) @@ -718,8 +720,46 @@ return GO_TO_ROOT; /* unreachable - just to reduce compiler warnings */ } -/* needs checking if needed end*/ +/* this is called from the playback thread so NO DRAWING! */ +void track_changed_callback(void *param) +{ + wps_state.id3 = (struct mp3entry*)param; + wps_state.nid3 = audio_next_track(); + wps_state.do_full_update = true; + + if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type + && strcmp(wps_state.id3->path, curr_cue->audio_filename)) + { + /* the current cuesheet isn't the right one any more */ + if (!strcmp(wps_state.id3->path, temp_cue->audio_filename)) { + /* We have the new cuesheet in memory (temp_cue), + let's make it the current one ! */ + memcpy(curr_cue, temp_cue, sizeof(struct cuesheet)); + } + else { + /* We need to parse the new cuesheet */ + + char cuepath[MAX_PATH]; + + if (look_for_cuesheet_file(wps_state.id3->path, cuepath) && + parse_cuesheet(cuepath, curr_cue)) + { + wps_state.id3->cuesheet_type = 1; + strcpy(curr_cue->audio_filename, wps_state.id3->path); + } + } + + cue_spoof_id3(curr_cue, wps_state.id3); + } +} +void nextid3available_callback(void* param) +{ + (void)param; + wps_state.nid3 = audio_next_track(); + wps_state.do_full_update = true; +} + /* wps_state */ static void wps_state_init(void) @@ -728,6 +768,10 @@ wps_state.paused = false; wps_state.id3 = NULL; wps_state.nid3 = NULL; + wps_state.do_full_update = true; + /* add the WPS track event callbacks, only needs doing once per boot */ + add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback); + add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, nextid3available_callback); } /* wps_state end*/ Index: apps/gui/gwps.h =================================================================== --- apps/gui/gwps.h (revision 19758) +++ apps/gui/gwps.h (working copy) @@ -469,6 +469,7 @@ bool wps_time_countup; struct mp3entry* id3; struct mp3entry* nid3; + bool do_full_update; }; Index: apps/appevents.h =================================================================== --- apps/appevents.h (revision 19758) +++ apps/appevents.h (working copy) @@ -34,6 +34,7 @@ PLAYBACK_EVENT_TRACK_BUFFER = (EVENT_CLASS_PLAYBACK|1), PLAYBACK_EVENT_TRACK_FINISH, PLAYBACK_EVENT_TRACK_CHANGE, + PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, }; /** Buffering events **/ Index: apps/mpeg.c =================================================================== --- apps/mpeg.c (revision 19758) +++ apps/mpeg.c (working copy) @@ -882,6 +882,9 @@ if (cuesheet_callback(filename)) track->id3.cuesheet_type = 1; + /* if this track is the next track then let the UI know it can get it */ + if (track_write_idx == track_read_idx + 1) + send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL); track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; debug_tags(); return track; Index: apps/playback.c =================================================================== --- apps/playback.c (revision 19758) +++ apps/playback.c (working copy) @@ -202,15 +202,16 @@ /* Possible arrangements of the buffer */ static int buffer_state = AUDIOBUF_STATE_TRASHED; /* Buffer state */ -/* Used to keep the WPS up-to-date during track transtition */ -static struct mp3entry prevtrack_id3; +/* These are used to store the current and next (or prev if the current is the last) + * mp3entry's in a round-robin system. This guarentees that the pointer returned + * by audio_current/next_track will be valid for the full duration of the + * currently playing track */ +static struct mp3entry mp3entry_buf[2]; +static struct mp3entry *thistrack_id3, /* the currently playing track */ + *othertrack_id3; /* prev track during track-change-transition, or end of playlist, + * next track otherwise */ +static struct mp3entry unbuffered_id3; /* the id3 for the first unbuffered track */ -/* Used to provide the codec with a pointer */ -static struct mp3entry curtrack_id3; - -/* Used to make next track info available while playing last track on buffer */ -static struct mp3entry lasttrack_id3; - /* Track info structure about songs in the file buffer (A/C-) */ struct track_info { int audio_hid; /* The ID for the track's buffer handle */ @@ -347,7 +348,10 @@ ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3); if (ret < 0 || ret != sizeof(struct mp3entry)) + { + // printf("boo\n"); return NULL; + } return id3; } @@ -565,24 +569,25 @@ cur_idx = (track_ridx + offset) & MAX_TRACK_MASK; - if (cur_idx == track_ridx && *curtrack_id3.path) + if (cur_idx == track_ridx && *thistrack_id3->path) { /* The usual case */ - return &curtrack_id3; + return thistrack_id3; } - else if (automatic_skip && offset == -1 && *prevtrack_id3.path) + else if (automatic_skip && offset == -1 && *othertrack_id3->path) { - /* We're in a track transition. The codec has moved on to the nex track, + /* We're in a track transition. The codec has moved on to the next track, but the audio being played is still the same (now previous) track. - prevtrack_id3.elapsed is being updated in an ISR by + othertrack_id3.elapsed is being updated in an ISR by codec_pcmbuf_position_callback */ - return &prevtrack_id3; + return othertrack_id3; } else if (tracks[cur_idx].id3_hid >= 0) { - /* Get the ID3 metadata from the main buffer */ - struct mp3entry *ret = bufgetid3(tracks[cur_idx].id3_hid); - if (ret) return ret; + /* The current track's info has been buffered but not read yet, so get it */ + if (bufread(tracks[cur_idx].id3_hid, sizeof(struct mp3entry), thistrack_id3) + == sizeof(struct mp3entry)) + return thistrack_id3; } /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info @@ -618,23 +623,29 @@ if (!audio_have_tracks()) return NULL; - if (wps_offset == -1 && *prevtrack_id3.path) + if (wps_offset == -1 && *othertrack_id3->path) { /* We're in a track transition. The next track for the WPS is the one currently being decoded. */ - return &curtrack_id3; + return othertrack_id3; } next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK; if (tracks[next_idx].id3_hid >= 0) - return bufgetid3(tracks[next_idx].id3_hid); + { + if (bufread(tracks[next_idx].id3_hid, sizeof(struct mp3entry), othertrack_id3) + == sizeof(struct mp3entry)) + return othertrack_id3; + else + return NULL; + } if (next_idx == track_widx) { /* The next track hasn't been buffered yet, so we return the static version of its metadata. */ - return &lasttrack_id3; + return &unbuffered_id3; } return NULL; @@ -821,7 +832,7 @@ if (was_playing) { /* Store the track resume position */ - offset = curtrack_id3.offset; + offset = thistrack_id3->offset; } /* Blast it - audio buffer will have to be setup again next time @@ -961,15 +972,15 @@ { /* This is called from an ISR, so be quick */ unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + - prevtrack_id3.elapsed; + othertrack_id3->elapsed; - if (time >= prevtrack_id3.length) + if (time >= othertrack_id3->length) { pcmbuf_set_position_callback(NULL); - prevtrack_id3.elapsed = prevtrack_id3.length; + othertrack_id3->elapsed = othertrack_id3->length; } else - prevtrack_id3.elapsed = time; + othertrack_id3->elapsed = time; } static void codec_set_elapsed_callback(unsigned int value) @@ -984,11 +995,11 @@ latency = pcmbuf_get_latency(); if (value < latency) - curtrack_id3.elapsed = 0; - else if (value - latency > curtrack_id3.elapsed || - value - latency < curtrack_id3.elapsed - 2) + thistrack_id3->elapsed = 0; + else if (value - latency > thistrack_id3->elapsed || + value - latency < thistrack_id3->elapsed - 2) { - curtrack_id3.elapsed = value - latency; + thistrack_id3->elapsed = value - latency; } } @@ -999,11 +1010,11 @@ if (ci.seek_time) return; - latency = pcmbuf_get_latency() * curtrack_id3.bitrate / 8; + latency = pcmbuf_get_latency() * thistrack_id3->bitrate / 8; if (value < latency) - curtrack_id3.offset = 0; + thistrack_id3->offset = 0; else - curtrack_id3.offset = value - latency; + thistrack_id3->offset = value - latency; } static void codec_advance_buffer_counters(size_t amount) @@ -1195,7 +1206,18 @@ { intptr_t result = Q_CODEC_REQUEST_FAILED; - prev_track_elapsed = curtrack_id3.elapsed; + prev_track_elapsed = thistrack_id3->elapsed; + + /* Codec calls this to start decoding the next track, so from this point on + * thistrack_id3 and othertrack_id3 need to be swapped... + * NOTE: on the last track of the playlist this causes one too many swaps + * so this needs to be unswapped some time later. + */ + struct mp3entry *temp = thistrack_id3; + thistrack_id3 = othertrack_id3; + othertrack_id3 = temp; + ci.id3 = thistrack_id3; + // printf("%d\n",__LINE__); #ifdef AB_REPEAT_ENABLE ab_end_of_track_report(); @@ -1245,7 +1267,7 @@ if (ci.stop_codec || !playing) return false; - prev_codectype = get_codec_base_type(curtrack_id3.codectype); + prev_codectype = get_codec_base_type(thistrack_id3->codectype); if (!codec_load_next_track()) return false; @@ -1253,10 +1275,10 @@ /* Seek to the beginning of the new track because if the struct mp3entry was buffered, "elapsed" might not be zero (if the track has been played already but not unbuffered) */ - codec_seek_buffer_callback(curtrack_id3.first_frame_offset); + codec_seek_buffer_callback(thistrack_id3->first_frame_offset); /* Check if the next codec is the same file. */ - if (prev_codectype == get_codec_base_type(curtrack_id3.codectype)) + if (prev_codectype == get_codec_base_type(thistrack_id3->codectype)) { logf("New track loaded"); codec_discard_codec_callback(); @@ -1264,7 +1286,7 @@ } else { - logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype); + logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype); return false; } } @@ -1381,8 +1403,10 @@ * triggering the WPS exit */ while(pcm_is_playing()) { - curtrack_id3.elapsed = - curtrack_id3.length - pcmbuf_get_latency(); + /* There has been one too many struct pointer swaps by now + * so even though it says othertrack_id3, its the correct one! */ + othertrack_id3->elapsed = + othertrack_id3->length - pcmbuf_get_latency(); sleep(1); } @@ -1403,7 +1427,7 @@ else { const char *codec_fn = - get_codec_filename(curtrack_id3.codectype); + get_codec_filename(thistrack_id3->codectype); if (codec_fn) { LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); @@ -1479,10 +1503,20 @@ if (*data == tracks[track_widx].id3_hid) { + int offset = ci.new_track + wps_offset; + int next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK; /* The metadata handle for the last loaded track has been buffered. We can ask the audio thread to load the rest of the track's data. */ LOGFQUEUE("audio >| audio Q_AUDIO_FINISH_LOAD"); queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0); + if (tracks[next_idx].id3_hid == *data) + send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL); + else if (tracks[(track_ridx + offset) & MAX_TRACK_MASK].id3_hid == *data) + { + // printf("buffered this id3\n"); + copy_mp3entry(thistrack_id3, bufgetid3(*data)); + send_event(PLAYBACK_EVENT_TRACK_CHANGE, thistrack_id3); + } } else { @@ -1532,15 +1566,15 @@ { /* Load the curent track's metadata into curtrack_id3 */ if (CUR_TI->id3_hid >= 0) - copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid)); + copy_mp3entry(thistrack_id3, bufgetid3(CUR_TI->id3_hid)); /* Reset current position */ - curtrack_id3.elapsed = 0; - curtrack_id3.offset = 0; + thistrack_id3->elapsed = 0; + thistrack_id3->offset = 0; /* Update the codec API */ ci.filesize = CUR_TI->filesize; - ci.id3 = &curtrack_id3; + ci.id3 = thistrack_id3; ci.curpos = 0; ci.taginfo_ready = &CUR_TI->taginfo_ready; } @@ -1606,7 +1640,7 @@ /* Load the codec directly from disk and save some memory. */ track_ridx = track_widx; ci.filesize = CUR_TI->filesize; - ci.id3 = &curtrack_id3; + ci.id3 = thistrack_id3; ci.taginfo_ready = &CUR_TI->taginfo_ready; ci.curpos = 0; LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); @@ -1696,10 +1730,10 @@ if (!trackname) { logf("End-of-playlist"); - memset(&lasttrack_id3, 0, sizeof(struct mp3entry)); + memset(&unbuffered_id3, 0, sizeof(struct mp3entry)); filling = STATE_END_OF_PLAYLIST; - if (curtrack_id3.length == 0 && curtrack_id3.filesize == 0) + if (thistrack_id3->length == 0 && thistrack_id3->filesize == 0) { /* Stop playback if no valid track was found. */ audio_stop_playback(); @@ -1730,7 +1764,7 @@ if (tracks[track_widx].id3_hid < 0) { /* Buffer is full. */ - get_metadata(&lasttrack_id3, fd, trackname); + get_metadata(&unbuffered_id3, fd, trackname); last_peek_offset--; close(fd); logf("buffer is full for now"); @@ -1741,9 +1775,16 @@ if (track_widx == track_ridx) { /* TODO: Superfluos buffering call? */ + // printf("%d\n",__LINE__); buf_request_buffer_handle(tracks[track_widx].id3_hid); - copy_mp3entry(&curtrack_id3, bufgetid3(tracks[track_widx].id3_hid)); - curtrack_id3.offset = offset; + struct mp3entry *id3 = bufgetid3(tracks[track_widx].id3_hid); + if (id3) + { + copy_mp3entry(thistrack_id3, id3); + thistrack_id3->offset = offset; + } + else + memset(thistrack_id3, 0, sizeof(struct mp3entry)); } if (start_play) @@ -1795,7 +1836,7 @@ struct mp3entry *track_id3; if (track_widx == track_ridx) - track_id3 = &curtrack_id3; + track_id3 = thistrack_id3; else track_id3 = bufgetid3(tracks[track_widx].id3_hid); @@ -1971,7 +2012,7 @@ ci.curpos = 0; if (!CUR_TI->taginfo_ready) - memset(&curtrack_id3, 0, sizeof(struct mp3entry)); + memset(thistrack_id3, 0, sizeof(struct mp3entry)); audio_fill_file_buffer(false, 0); } @@ -1986,7 +2027,7 @@ bool forward; /* Now it's good time to send track finish events. */ - send_event(PLAYBACK_EVENT_TRACK_FINISH, &curtrack_id3); + send_event(PLAYBACK_EVENT_TRACK_FINISH, thistrack_id3); if (dir_skip) { dir_skip = false; @@ -2033,12 +2074,12 @@ /* Save the track metadata to allow the WPS to display it while PCM finishes playing that track */ - copy_mp3entry(&prevtrack_id3, &curtrack_id3); + //copy_mp3entry(&prevtrack_id3, &curtrack_id3); /* Update the main buffer copy of the track metadata with the one the codec has been using (for the unbuffer callbacks) */ if (CUR_TI->id3_hid >= 0) - copy_mp3entry(bufgetid3(CUR_TI->id3_hid), &curtrack_id3); + copy_mp3entry(bufgetid3(CUR_TI->id3_hid), thistrack_id3); /* Save a pointer to the old track to allow later clearing */ prev_ti = CUR_TI; @@ -2174,7 +2215,7 @@ /* TODO: Create auto bookmark too? */ - prev_track_elapsed = curtrack_id3.elapsed; + prev_track_elapsed = othertrack_id3->elapsed; remove_event(BUFFER_EVENT_BUFFER_LOW, buffering_low_buffer_callback); } @@ -2191,8 +2232,6 @@ /* Close all tracks */ audio_release_tracks(); - - memset(&curtrack_id3, 0, sizeof(struct mp3entry)); } static void audio_play_start(size_t offset) @@ -2314,7 +2353,7 @@ automatic_skip = false; /* Invalidate prevtrack_id3 */ - prevtrack_id3.path[0] = 0; + othertrack_id3->path[0] = 0; if (prev_ti && prev_ti->audio_hid < 0) { @@ -2330,8 +2369,8 @@ } } - send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3); - + send_event(PLAYBACK_EVENT_TRACK_CHANGE, thistrack_id3); + track_changed = true; playlist_update_resume_info(audio_current_track()); } @@ -2540,7 +2579,7 @@ void audio_init(void) { unsigned int audio_thread_id; - + /* Can never do this twice */ if (audio_is_initialized) { @@ -2576,6 +2615,9 @@ ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP, CODEC_IDX_AUDIO); + thistrack_id3 = &mp3entry_buf[0]; + othertrack_id3 = &mp3entry_buf[1]; + /* initialize the buffer */ filebuf = audiobuf;