From 843c7efaf8c953fc3bec40a7da0be3a5da9950df Mon Sep 17 00:00:00 2001 From: Jonathan Gordon Date: Mon, 6 Apr 2009 00:39:43 +0000 Subject: 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 --- apps/appevents.h | 1 + apps/gui/gwps-common.c | 39 ++------- apps/gui/gwps.c | 51 +++++++++++- apps/gui/gwps.h | 1 + apps/gui/wps_parser.c | 44 +++++----- apps/iap.c | 6 +- apps/mpeg.c | 5 ++ apps/playback.c | 210 +++++++++++++++++++++++------------------------- apps/plugin.c | 1 - apps/plugin.h | 5 +- firmware/export/audio.h | 1 - firmware/export/iap.h | 2 +- 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 { 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 -- cgit