Rewritten playback event handling. Should fix runtime statistics gathering.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16546 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2008-03-07 22:56:51 +00:00
parent aafa321d31
commit 2ccdc48ee9
4 changed files with 71 additions and 68 deletions

View file

@ -210,8 +210,6 @@ struct track_info {
size_t filesize; /* File total length */ size_t filesize; /* File total length */
bool taginfo_ready; /* Is metadata read */ bool taginfo_ready; /* Is metadata read */
bool event_sent; /* Was this track's buffered event sent */
}; };
static struct track_info tracks[MAX_TRACK]; 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; static bool codec_requested_stop = false;
/* Callbacks which applications or plugins may set */ struct playback_event {
/* When the playing track has changed from the user's perspective */ enum PLAYBACK_EVENT_TYPE type;
void (*track_changed_callback)(struct mp3entry *id3) = NULL; void (*callback)(void *data);
/* When a track has been buffered */ };
void (*track_buffer_callback)(struct mp3entry *id3) = NULL;
/* When a track's buffer has been overwritten or cleared */ struct playback_event events[PLAYBACK_MAX_EVENTS];
void (*track_unbuffer_callback)(struct mp3entry *id3) = NULL;
static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */ 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->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)) if (bufclose(track->id3_hid))
track->id3_hid = -1; track->id3_hid = -1;
else else
@ -381,7 +373,6 @@ static bool clear_track_info(struct track_info *track)
track->filesize = 0; track->filesize = 0;
track->taginfo_ready = false; track->taginfo_ready = false;
track->event_sent = false;
return true; return true;
} }
@ -1456,6 +1447,51 @@ static void codec_thread(void)
/* --- Audio thread --- */ /* --- 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) static bool audio_have_tracks(void)
{ {
return (audio_track_count() != 0); 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, /* If the track is buffered, conditionally clear/notify,
* otherwise clear the track if that option is selected */ * 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]); 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 (get_metadata(&id3, fd, trackname))
{ {
if (track_buffer_callback) send_event(PLAYBACK_EVENT_TRACK_BUFFER, &id3);
track_buffer_callback(&id3);
tracks[track_widx].id3_hid = tracks[track_widx].id3_hid =
bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3); bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
@ -1910,30 +1945,6 @@ static bool audio_load_track(int offset, bool start_play)
return true; 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) static void audio_fill_file_buffer(bool start_play, size_t offset)
{ {
struct queue_event ev; 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()) if (!had_next_track && audio_next_track())
track_changed = true; track_changed = true;
audio_generate_postbuffer_events();
} }
static void audio_rebuffer(void) static void audio_rebuffer(void)
@ -2012,6 +2022,9 @@ static int audio_check_new_track(void)
bool forward; bool forward;
bool end_of_playlist; /* Temporary flag, not the same as playlist_end */ 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) if (dir_skip)
{ {
dir_skip = false; dir_skip = false;
@ -2173,21 +2186,6 @@ skip_done:
return Q_CODEC_REQUEST_COMPLETE; 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) unsigned long audio_prev_elapsed(void)
{ {
return prev_track_elapsed; return prev_track_elapsed;
@ -2404,8 +2402,7 @@ static void audio_finalise_track_change(void)
bufgetid3(prev_ti->id3_hid)->elapsed = 0; bufgetid3(prev_ti->id3_hid)->elapsed = 0;
} }
if (track_changed_callback) send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3);
track_changed_callback(&curtrack_id3);
track_changed = true; track_changed = true;
playlist_update_resume_info(audio_current_track()); playlist_update_resume_info(audio_current_track());

View file

@ -39,11 +39,17 @@
#define MAX_TRACK_MASK (MAX_TRACK-1) #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 */ /* Functions */
const char * get_codec_filename(int cod_spec); const char * get_codec_filename(int cod_spec);
void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)); void playback_add_event(enum PLAYBACK_EVENT_TYPE type, void (*handler));
void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3)); void playback_remove_event(enum PLAYBACK_EVENT_TYPE type, void (*handler));
void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3));
void voice_wait(void); void voice_wait(void);
#if CONFIG_CODEC == SWCODEC /* This #ifdef is better here than gui/gwps.c */ #if CONFIG_CODEC == SWCODEC /* This #ifdef is better here than gui/gwps.c */

View file

@ -224,7 +224,7 @@ int scrobbler_init(void)
scrobbler_cache = buffer_alloc(SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN); 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; cache_pos = 0;
pending = false; pending = false;
scrobbler_initialised = true; scrobbler_initialised = true;
@ -259,7 +259,7 @@ void scrobbler_shutdown(void)
if (scrobbler_initialised) if (scrobbler_initialised)
{ {
audio_set_track_changed_event(NULL); playback_remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
scrobbler_initialised = false; scrobbler_initialised = false;
} }
} }

View file

@ -660,7 +660,7 @@ static void tagtree_buffer_event(struct mp3entry *id3)
tagcache_search_finish(&tcs); tagcache_search_finish(&tcs);
} }
static void tagtree_unbuffer_event(struct mp3entry *id3) static void tagtree_track_finish_event(struct mp3entry *id3)
{ {
long playcount; long playcount;
long playtime; long playtime;
@ -924,8 +924,8 @@ void tagtree_init(void)
root_menu = 0; root_menu = 0;
uniqbuf = buffer_alloc(UNIQBUF_SIZE); uniqbuf = buffer_alloc(UNIQBUF_SIZE);
audio_set_track_buffer_event(tagtree_buffer_event); playback_add_event(PLAYBACK_EVENT_TRACK_BUFFER, tagtree_buffer_event);
audio_set_track_unbuffer_event(tagtree_unbuffer_event); playback_add_event(PLAYBACK_EVENT_TRACK_FINISH, tagtree_track_finish_event);
} }
static bool show_search_progress(bool init, int count) static bool show_search_progress(bool init, int count)