mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-17 09:02:38 -05:00
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:
parent
aafa321d31
commit
2ccdc48ee9
4 changed files with 71 additions and 68 deletions
117
apps/playback.c
117
apps/playback.c
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue