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 { PLAYBACK_EVENT_TRACK_BUFFER = (EVENT_CLASS_PLAYBACK|1), PLAYBACK_EVENT_TRACK_FINISH, PLAYBACK_EVENT_TRACK_CHANGE, + PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, }; /** 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) bool gui_wps_update(struct gui_wps *gwps) { - bool track_changed = audio_has_changed_track(); struct mp3entry *id3 = gwps->state->id3; - - gwps->state->nid3 = audio_next_track(); - if (track_changed) - { - gwps->state->id3 = id3 = audio_current_track(); - - if (cuesheet_is_enabled() && id3->cuesheet_type - && strcmp(id3->path, curr_cue->audio_filename)) - { - /* the current cuesheet isn't the right one any more */ - /* We need to parse the new cuesheet */ - - char cuepath[MAX_PATH]; - - if (look_for_cuesheet_file(id3->path, cuepath) && - parse_cuesheet(cuepath, curr_cue)) - { - id3->cuesheet_type = 1; - strcpy(curr_cue->audio_filename, id3->path); - } - - cue_spoof_id3(curr_cue, id3); - } - } - + bool retval; if (cuesheet_is_enabled() && id3->cuesheet_type && (id3->elapsed < curr_cue->curr_track->offset || (curr_cue->curr_track_idx < curr_cue->track_count - 1 @@ -382,17 +357,15 @@ bool gui_wps_update(struct gui_wps *gwps) { /* We've changed tracks within the cuesheet : we need to update the ID3 info and refresh the WPS */ - - track_changed = true; + gwps->state->do_full_update = true; cue_find_current_track(curr_cue, id3->elapsed); cue_spoof_id3(curr_cue, id3); } - if (track_changed) - gwps->display->stop_scroll(); - - return gui_wps_redraw(gwps, 0, - track_changed ? WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); + retval = gui_wps_redraw(gwps, 0, + gwps->state->do_full_update ? + WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); + return retval; } 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]; /* initial setup of wps_data */ static void wps_state_init(void); +static void track_changed_callback(void *param); +static void nextid3available_callback(void* param); static void change_dir(int direction) { @@ -246,7 +248,7 @@ long gui_wps_show(void) long restoretimer = RESTORE_WPS_INSTANTLY; /* timer to delay screen redraw temporarily */ bool exit = false; bool bookmark = false; - bool update_track = false; + bool update_track = false, partial_update = false; int i; long last_left = 0, last_right = 0; wps_state_init(); @@ -651,7 +653,7 @@ long gui_wps_show(void) restore = true; break; case ACTION_NONE: /* Timeout */ - update_track = true; + partial_update = true; ffwd_rew(button); /* hopefully fix the ffw/rwd bug */ break; #ifdef HAVE_RECORDING @@ -671,13 +673,21 @@ long gui_wps_show(void) break; } - if (update_track) + if (wps_state.do_full_update || partial_update || update_track) { + if (update_track) + { + wps_state.do_full_update = true; + wps_state.id3 = audio_current_track(); + wps_state.nid3 = audio_next_track(); + } FOR_NB_SCREENS(i) { gui_wps_update(&gui_wps[i]); } + wps_state.do_full_update = false; update_track = false; + partial_update = false; } if (restore && wps_state.id3 && @@ -723,7 +733,36 @@ long gui_wps_show(void) 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! */ +static void track_changed_callback(void *param) +{ + wps_state.id3 = (struct mp3entry*)param; + wps_state.nid3 = audio_next_track(); + + 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 */ + /* 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); + } + wps_state.do_full_update = true; +} +static void nextid3available_callback(void* param) +{ + (void)param; + wps_state.nid3 = audio_next_track(); + wps_state.do_full_update = true; +} /* wps_state */ @@ -733,6 +772,10 @@ static void wps_state_init(void) wps_state.paused = false; wps_state.id3 = NULL; wps_state.nid3 = NULL; + wps_state.do_full_update = true; + /* add the WPS track event callbacks */ + add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback); + add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, nextid3available_callback); } /* 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 bool wps_time_countup; struct mp3entry* id3; struct mp3entry* nid3; + bool do_full_update; }; 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[] = { parse_dir_level }, /* next file */ - { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_DYNAMIC, + { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_STATIC, parse_dir_level }, /* current metadata */ @@ -242,18 +242,18 @@ static const struct wps_tag all_tags[] = { { WPS_TOKEN_METADATA_COMMENT, "iC", WPS_REFRESH_STATIC, NULL }, /* next metadata */ - { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_STATIC, NULL }, #if (CONFIG_CODEC != MAS3507D) { 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 @@ #include "system.h" #include "kernel.h" #include "serial.h" +#include "appevents.h" #include "playlist.h" #include "playback.h" @@ -80,6 +81,7 @@ void iap_setup(int ratenum) iap_setupflag = true; iap_remotebtn = BUTTON_NONE; tick_add_task(iap_task); + add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed); } void iap_bitrate_set(int ratenum) @@ -175,8 +177,10 @@ int iap_getc(unsigned char x) return newpkt; } -void iap_track_changed(void) +/* called by playback when the next track starts */ +void iap_track_changed(void *ignored) { + (void)ignored; iap_changedctr = 1; } 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) static struct trackdata *add_track_to_tag_list(const char *filename) { struct trackdata *track; + bool send_nid3_event; if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES) { @@ -882,7 +883,11 @@ static struct trackdata *add_track_to_tag_list(const char *filename) 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 */ + send_nid3_event = (track_write_idx == track_read_idx + 1); track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; + if (send_nid3_event) + send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL); debug_tags(); return track; } 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-) */ /* 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; - -/* 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; +/* 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 */ /* Track info structure about songs in the file buffer (A/C-) */ struct track_info { @@ -232,10 +233,6 @@ static int track_widx = 0; /* Track being buffered (A) */ static struct track_info *prev_ti = NULL; /* Pointer to the previously played track */ -/* Set by the audio thread when the current track information has updated - * and the WPS may need to update its cached information */ -static bool track_changed = false; - /* Information used only for filling the buffer */ /* Playlist steps from playing track to next track to be buffered (A) */ static int last_peek_offset = 0; @@ -567,24 +564,25 @@ struct mp3entry* audio_current_track(void) 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, - but the audio being played is still the same (now previous) track. - prevtrack_id3.elapsed is being updated in an ISR by - codec_pcmbuf_position_callback */ - return &prevtrack_id3; + /* 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. + othertrack_id3.elapsed is being updated in an ISR by + codec_pcmbuf_position_callback */ + 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), &temp_id3) + == sizeof(struct mp3entry)) + return &temp_id3; } /* 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) if (!audio_have_tracks()) return NULL; - if (wps_offset == -1 && *prevtrack_id3.path) + if (wps_offset == -1 && *thistrack_id3->path) { /* We're in a track transition. The next track for the WPS is the one currently being decoded. */ - return &curtrack_id3; + return thistrack_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; } -bool audio_has_changed_track(void) -{ - if (track_changed) - { -#ifdef IPOD_ACCESSORY_PROTOCOL - iap_track_changed(); -#endif - track_changed = false; - return true; - } - - return false; -} - void audio_play(long offset) { logf("audio_play"); @@ -705,7 +695,6 @@ void audio_skip(int direction) queue_post(&audio_queue, Q_AUDIO_SKIP, direction); /* Update wps while our message travels inside deep playback queues. */ wps_offset += direction; - track_changed = true; } else { @@ -823,7 +812,7 @@ void audio_set_crossfade(int enable) 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 @@ -963,15 +952,15 @@ static void codec_pcmbuf_position_callback(size_t size) { /* 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) @@ -986,11 +975,11 @@ static void codec_set_elapsed_callback(unsigned int value) 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; } } @@ -1001,11 +990,11 @@ static void codec_set_offset_callback(size_t value) 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) @@ -1197,7 +1186,7 @@ static bool codec_load_next_track(void) { intptr_t result = Q_CODEC_REQUEST_FAILED; - prev_track_elapsed = curtrack_id3.elapsed; + prev_track_elapsed = thistrack_id3->elapsed; #ifdef AB_REPEAT_ENABLE ab_end_of_track_report(); @@ -1247,18 +1236,16 @@ static bool codec_request_next_track_callback(void) 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; /* 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(); @@ -1266,7 +1253,7 @@ static bool codec_request_next_track_callback(void) } else { - logf("New codec:%d/%d", curtrack_id3.codectype, prev_codectype); + logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype); return false; } } @@ -1293,6 +1280,7 @@ static void codec_thread(void) audio_codec_loaded = true; ci.stop_codec = false; status = codec_load_file((const char *)ev.data, &ci); + LOGFQUEUE("codec_load_file %s %d\n", (const char *)ev.data, status); break; case Q_CODEC_LOAD: @@ -1312,6 +1300,7 @@ static void codec_thread(void) audio_codec_loaded = true; ci.stop_codec = false; status = codec_load_buf(CUR_TI->codec_hid, &ci); + LOGFQUEUE("codec_load_buf %d\n", status); break; case Q_CODEC_DO_CALLBACK: @@ -1362,7 +1351,7 @@ static void codec_thread(void) { if (!ci.new_track) { - logf("Codec failure"); + logf("Codec failure, %d %d", ci.new_track, status); splash(HZ*2, "Codec failure"); } @@ -1383,8 +1372,10 @@ static void codec_thread(void) * 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); } @@ -1405,7 +1396,7 @@ static void codec_thread(void) 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"); @@ -1481,10 +1472,14 @@ static void buffering_handle_finished_callback(int *data) 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 { @@ -1534,15 +1529,15 @@ static void audio_update_trackinfo(void) { /* 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; } @@ -1608,7 +1603,7 @@ static bool audio_loadcodec(bool start_play) /* 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"); @@ -1698,10 +1693,10 @@ static bool audio_load_track(size_t offset, bool start_play) 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(); @@ -1720,7 +1715,6 @@ static bool audio_load_track(size_t offset, bool start_play) { buf_set_watermark(filebuflen/2); dsp_configure(ci.dsp, DSP_RESET, 0); - track_changed = true; playlist_update_resume_info(audio_current_track()); } @@ -1732,7 +1726,7 @@ static bool audio_load_track(size_t offset, bool start_play) 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"); @@ -1744,13 +1738,18 @@ static bool audio_load_track(size_t offset, bool start_play) { /* TODO: Superfluos buffering call? */ 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) { - track_changed = true; playlist_update_resume_info(audio_current_track()); } } @@ -1780,7 +1779,7 @@ static void audio_finish_load_track(void) 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); @@ -1935,8 +1934,6 @@ static void audio_finish_load_track(void) static void audio_fill_file_buffer(bool start_play, size_t offset) { - bool had_next_track = audio_next_track() != NULL; - filling = STATE_FILLING; trigger_cpu_boost(); @@ -1959,9 +1956,6 @@ static void audio_fill_file_buffer(bool start_play, size_t offset) playlist_update_resume_info(audio_current_track()); audio_load_track(offset, start_play); - - if (!had_next_track && audio_next_track()) - track_changed = true; } static void audio_rebuffer(void) @@ -1982,7 +1976,7 @@ static void audio_rebuffer(void) 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); } @@ -1995,9 +1989,16 @@ static int audio_check_new_track(void) int old_track_ridx = track_ridx; int i, idx; bool forward; + struct mp3entry *temp = thistrack_id3; /* 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); + /* swap the mp3entry pointers */ + thistrack_id3 = othertrack_id3; + othertrack_id3 = temp; + ci.id3 = thistrack_id3; + memset(thistrack_id3, 0, sizeof(struct mp3entry)); + if (dir_skip) { dir_skip = false; @@ -2035,22 +2036,23 @@ static int audio_check_new_track(void) LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED"); return Q_CODEC_REQUEST_FAILED; } - + if (new_playlist) { ci.new_track = 1; new_playlist = false; } - /* Save the track metadata to allow the WPS to display it - while PCM finishes playing that track */ - copy_mp3entry(&prevtrack_id3, &curtrack_id3); - + /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * 1) why are we doing this? + * 2) thistrack_id3 has already been cleared anyway */ /* 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); + /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME */ + + /* Save a pointer to the old track to allow later clearing */ prev_ti = CUR_TI; @@ -2079,7 +2081,6 @@ static int audio_check_new_track(void) if (automatic_skip) { wps_offset = -ci.new_track; - track_changed = true; } /* If it is not safe to even skip this many track entries */ @@ -2185,7 +2186,7 @@ static void audio_stop_playback(void) /* 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); } @@ -2202,8 +2203,6 @@ static void audio_stop_playback(void) /* Close all tracks */ audio_release_tracks(); - - memset(&curtrack_id3, 0, sizeof(struct mp3entry)); } static void audio_play_start(size_t offset) @@ -2219,8 +2218,6 @@ static void audio_play_start(size_t offset) paused = false; audio_stop_codec_flush(); - track_changed = true; - playing = true; track_load_started = false; @@ -2325,25 +2322,15 @@ static void audio_finalise_track_change(void) automatic_skip = false; /* Invalidate prevtrack_id3 */ - prevtrack_id3.path[0] = 0; + memset(othertrack_id3, 0, sizeof(struct mp3entry)); if (prev_ti && prev_ti->audio_hid < 0) { /* No audio left so we clear all the track info. */ clear_track_info(prev_ti); } - - if (prev_ti && prev_ti->id3_hid >= 0) - { - /* Reset the elapsed time to force the progressbar to be empty if - the user skips back to this track */ - bufgetid3(prev_ti->id3_hid)->elapsed = 0; - } } - - send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3); - - track_changed = true; + send_event(PLAYBACK_EVENT_TRACK_CHANGE, thistrack_id3); playlist_update_resume_info(audio_current_track()); } @@ -2588,6 +2575,9 @@ void audio_init(void) 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; 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 = { audio_ff_rewind, audio_next_track, audio_status, - audio_has_changed_track, audio_current_track, audio_flush_and_reload_tracks, 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); #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 146 +#define PLUGIN_API_VERSION 147 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any new function which are "waiting" at the end of the function table) */ -#define PLUGIN_MIN_API_VERSION 146 +#define PLUGIN_MIN_API_VERSION 147 /* plugin return codes */ enum plugin_status { @@ -588,7 +588,6 @@ struct plugin_api { void (*audio_ff_rewind)(long newtime); struct mp3entry* (*audio_next_track)(void); int (*audio_status)(void); - bool (*audio_has_changed_track)(void); struct mp3entry* (*audio_current_track)(void); void (*audio_flush_and_reload_tracks)(void); 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); void audio_flush_and_reload_tracks(void); struct mp3entry* audio_current_track(void); struct mp3entry* audio_next_track(void); -bool audio_has_changed_track(void); void audio_get_debugdata(struct audio_debug *dbgdata); #ifdef HAVE_DISK_STORAGE void 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); extern void iap_bitrate_set(int ratenum); extern void iap_periodic(void); extern void iap_handlepkt(void); -extern void iap_track_changed(void); +extern void iap_track_changed(void *ignored); #endif