From 2ccdc48ee943f1506809e94df990873cb937bd1a Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Fri, 7 Mar 2008 22:56:51 +0000 Subject: Rewritten playback event handling. Should fix runtime statistics gathering. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16546 a1c6a512-1295-4272-9138-f99709370657 --- apps/playback.c | 117 +++++++++++++++++++++++++++---------------------------- apps/playback.h | 12 ++++-- apps/scrobbler.c | 4 +- apps/tagtree.c | 6 +-- 4 files changed, 71 insertions(+), 68 deletions(-) diff --git a/apps/playback.c b/apps/playback.c index f757f4ae08..f66fd2954a 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -210,8 +210,6 @@ struct track_info { size_t filesize; /* File total length */ bool taginfo_ready; /* Is metadata read */ - - bool event_sent; /* Was this track's buffered event sent */ }; static struct track_info tracks[MAX_TRACK]; @@ -247,13 +245,12 @@ static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer */ static bool codec_requested_stop = false; -/* Callbacks which applications or plugins may set */ -/* When the playing track has changed from the user's perspective */ -void (*track_changed_callback)(struct mp3entry *id3) = NULL; -/* When a track has been buffered */ -void (*track_buffer_callback)(struct mp3entry *id3) = NULL; -/* When a track's buffer has been overwritten or cleared */ -void (*track_unbuffer_callback)(struct mp3entry *id3) = NULL; +struct playback_event { + enum PLAYBACK_EVENT_TYPE type; + void (*callback)(void *data); +}; + +struct playback_event events[PLAYBACK_MAX_EVENTS]; static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */ @@ -352,11 +349,6 @@ static bool clear_track_info(struct track_info *track) } if (track->id3_hid >= 0) { - if (track->event_sent && track_unbuffer_callback) { - /* If there is an unbuffer callback, call it */ - track_unbuffer_callback(bufgetid3(track->id3_hid)); - } - if (bufclose(track->id3_hid)) track->id3_hid = -1; else @@ -381,7 +373,6 @@ static bool clear_track_info(struct track_info *track) track->filesize = 0; track->taginfo_ready = false; - track->event_sent = false; return true; } @@ -1456,6 +1447,51 @@ static void codec_thread(void) /* --- Audio thread --- */ +void playback_add_event(enum PLAYBACK_EVENT_TYPE type, void (*handler)) +{ + int i; + + /* Try to find a free slot. */ + for (i = 0; i < PLAYBACK_MAX_EVENTS; i++) + { + if (events[i].callback == NULL) + { + events[i].type = type; + events[i].callback = handler; + return; + } + } + + panicf("playback event line full"); +} + +void playback_remove_event(enum PLAYBACK_EVENT_TYPE type, void (*handler)) +{ + int i; + + for (i = 0; i < PLAYBACK_MAX_EVENTS; i++) + { + if (events[i].type == type && events[i].callback == handler) + { + events[i].callback = NULL; + return; + } + } + + panicf("playback event not found"); +} + +static void send_event(enum PLAYBACK_EVENT_TYPE type, void *data) +{ + int i; + + for (i = 0; i < PLAYBACK_MAX_EVENTS; i++) + { + if (events[i].type == type && events[i].callback != NULL) + events[i].callback(data); + } +} + static bool audio_have_tracks(void) { return (audio_track_count() != 0); @@ -1546,7 +1582,7 @@ static void audio_clear_track_entries(bool clear_unbuffered) /* If the track is buffered, conditionally clear/notify, * otherwise clear the track if that option is selected */ - if (tracks[cur_idx].event_sent || clear_unbuffered) + if (clear_unbuffered) clear_track_info(&tracks[cur_idx]); } } @@ -1750,8 +1786,7 @@ static bool audio_load_track(int offset, bool start_play) { if (get_metadata(&id3, fd, trackname)) { - if (track_buffer_callback) - track_buffer_callback(&id3); + send_event(PLAYBACK_EVENT_TRACK_BUFFER, &id3); tracks[track_widx].id3_hid = bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3); @@ -1910,30 +1945,6 @@ static bool audio_load_track(int offset, bool start_play) return true; } -/* Send callback events to notify about new tracks. */ -static void audio_generate_postbuffer_events(void) -{ - int cur_idx; - - logf("Postbuffer:%d/%d",track_ridx,track_widx); - - if (audio_have_tracks()) - { - cur_idx = track_ridx; - - while (1) { - if (!tracks[cur_idx].event_sent) - { - /* Mark the event 'sent' even if we don't really send one */ - tracks[cur_idx].event_sent = true; - } - if (cur_idx == track_widx) - break; - cur_idx = (cur_idx + 1) & MAX_TRACK_MASK; - } - } -} - static void audio_fill_file_buffer(bool start_play, size_t offset) { struct queue_event ev; @@ -1978,7 +1989,6 @@ static void audio_fill_file_buffer(bool start_play, size_t offset) if (!had_next_track && audio_next_track()) track_changed = true; - audio_generate_postbuffer_events(); } static void audio_rebuffer(void) @@ -2012,6 +2022,9 @@ static int audio_check_new_track(void) bool forward; bool end_of_playlist; /* Temporary flag, not the same as playlist_end */ + /* Now it's good time to send track unbuffer events. */ + send_event(PLAYBACK_EVENT_TRACK_FINISH, &curtrack_id3); + if (dir_skip) { dir_skip = false; @@ -2173,21 +2186,6 @@ skip_done: return Q_CODEC_REQUEST_COMPLETE; } -void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3)) -{ - track_buffer_callback = handler; -} - -void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3)) -{ - track_unbuffer_callback = handler; -} - -void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)) -{ - track_changed_callback = handler; -} - unsigned long audio_prev_elapsed(void) { return prev_track_elapsed; @@ -2404,8 +2402,7 @@ static void audio_finalise_track_change(void) bufgetid3(prev_ti->id3_hid)->elapsed = 0; } - if (track_changed_callback) - track_changed_callback(&curtrack_id3); + send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3); track_changed = true; playlist_update_resume_info(audio_current_track()); diff --git a/apps/playback.h b/apps/playback.h index b005e63b3c..13a959a0ca 100644 --- a/apps/playback.h +++ b/apps/playback.h @@ -39,11 +39,17 @@ #define MAX_TRACK_MASK (MAX_TRACK-1) +#define PLAYBACK_MAX_EVENTS 4 +enum PLAYBACK_EVENT_TYPE { + PLAYBACK_EVENT_TRACK_BUFFER, + PLAYBACK_EVENT_TRACK_FINISH, + PLAYBACK_EVENT_TRACK_CHANGE, +}; + /* Functions */ const char * get_codec_filename(int cod_spec); -void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)); -void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3)); -void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3)); +void playback_add_event(enum PLAYBACK_EVENT_TYPE type, void (*handler)); +void playback_remove_event(enum PLAYBACK_EVENT_TYPE type, void (*handler)); void voice_wait(void); #if CONFIG_CODEC == SWCODEC /* This #ifdef is better here than gui/gwps.c */ diff --git a/apps/scrobbler.c b/apps/scrobbler.c index 01c704afab..6398fd1741 100644 --- a/apps/scrobbler.c +++ b/apps/scrobbler.c @@ -224,7 +224,7 @@ int scrobbler_init(void) scrobbler_cache = buffer_alloc(SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN); - audio_set_track_changed_event(&scrobbler_change_event); + playback_add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event); cache_pos = 0; pending = false; scrobbler_initialised = true; @@ -259,7 +259,7 @@ void scrobbler_shutdown(void) if (scrobbler_initialised) { - audio_set_track_changed_event(NULL); + playback_remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event); scrobbler_initialised = false; } } diff --git a/apps/tagtree.c b/apps/tagtree.c index 17401f3fbb..86aa8069c7 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -660,7 +660,7 @@ static void tagtree_buffer_event(struct mp3entry *id3) tagcache_search_finish(&tcs); } -static void tagtree_unbuffer_event(struct mp3entry *id3) +static void tagtree_track_finish_event(struct mp3entry *id3) { long playcount; long playtime; @@ -924,8 +924,8 @@ void tagtree_init(void) root_menu = 0; uniqbuf = buffer_alloc(UNIQBUF_SIZE); - audio_set_track_buffer_event(tagtree_buffer_event); - audio_set_track_unbuffer_event(tagtree_unbuffer_event); + playback_add_event(PLAYBACK_EVENT_TRACK_BUFFER, tagtree_buffer_event); + playback_add_event(PLAYBACK_EVENT_TRACK_FINISH, tagtree_track_finish_event); } static bool show_search_progress(bool init, int count) -- cgit v1.2.3