From dece414749fa7155020e5794debfcb657e79fa66 Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Sun, 21 Aug 2005 21:15:32 +0000 Subject: Hooked up the runtime database on archos. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7376 a1c6a512-1295-4272-9138-f99709370657 --- apps/database.c | 17 +++---- firmware/export/mpeg.h | 7 +++ firmware/mpeg.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 132 insertions(+), 17 deletions(-) diff --git a/apps/database.c b/apps/database.c index 1691e2221b..90cdc37f2c 100644 --- a/apps/database.c +++ b/apps/database.c @@ -43,7 +43,13 @@ #include "keyboard.h" #include "database.h" #include "autoconf.h" + +#if CONFIG_HWCODEC == MASNONE #include "playback.h" +#else +#include "mpeg.h" +#endif + #include "logf.h" /* internal functions */ @@ -328,9 +334,6 @@ void rundb_buffer_track(struct mp3entry *id, bool last_track) { int rundb_init(void) { -#if CONFIG_HWCODEC != MASNONE - return -1; -#else unsigned char* ptr = (char*)&rundbheader.version; #ifdef ROCKBOX_LITTLE_ENDIAN int i, *p; @@ -376,17 +379,13 @@ int rundb_init(void) } rundb_initialized = 1; -/* hooks disabled for archos, rendering the runtime database not working, - * re enable when these callbacks are implemented in mpeg.c */ -#if CONFIG_HWCODEC == MASNONE audio_set_track_buffer_event(&rundb_buffer_track); audio_set_track_changed_event(&rundb_track_change); audio_set_track_unbuffer_event(&rundb_unbuffer_track); logf("rundb inited."); -#endif + rundbsize=lseek(rundb_fd,0,SEEK_END); return 0; -#endif } void rundb_shutdown(void) @@ -394,11 +393,9 @@ void rundb_shutdown(void) if (rundb_fd >= 0) close(rundb_fd); rundb_initialized = 0; -#if CONFIG_HWCODEC == MASNONE audio_set_track_buffer_event(NULL); audio_set_track_unbuffer_event(NULL); audio_set_track_changed_event(NULL); -#endif } void writerundbheader(void) diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h index 71e61a08c9..d8dea3d143 100644 --- a/firmware/export/mpeg.h +++ b/firmware/export/mpeg.h @@ -20,6 +20,7 @@ #define _MPEG_H_ #include +#include "id3.h" #define MPEG_SWAP_CHUNKSIZE 0x2000 #define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we @@ -65,4 +66,10 @@ void rec_tick(void); void playback_tick(void); /* FixMe: get rid of this, use mp3_get_playtime() */ void mpeg_id3_options(bool _v1first); +void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)); +void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, + bool last_track)); +void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, + bool last_track)); + #endif diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 0406376e00..575ba29fe3 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c @@ -84,6 +84,9 @@ extern int playlist_update_resume_info(const struct mp3entry* id3); #define MPEG_SAVE_DATA 102 #define MPEG_STOP_DONE 103 +/* indicator for MPEG_NEED_DATA */ +#define GENERATE_UNBUFFER_EVENTS ((void*)1) + /* list of tracks in memory */ #define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */ #define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1) @@ -93,6 +96,7 @@ struct trackdata struct mp3entry id3; int mempos; int load_ahead_index; + bool event_sent; }; static struct trackdata trackdata[MAX_TRACK_ENTRIES]; @@ -105,6 +109,11 @@ static int track_read_idx = 0; static int track_write_idx = 0; #endif /* !SIMULATOR */ +/* Callback function to call when current track has really changed. */ +void (*track_changed_callback)(struct mp3entry *id3); +void (*track_buffer_callback)(struct mp3entry *id3, bool last_track); +void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track); + static const char mpeg_thread_name[] = "mpeg"; static unsigned int mpeg_errno; @@ -400,8 +409,89 @@ unsigned long mpeg_get_last_header(void) #endif /* !SIMULATOR */ } +void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, + bool last_track)) +{ + track_buffer_callback = handler; +} + +void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, + bool last_track)) +{ + track_unbuffer_callback = handler; +} + +void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)) +{ + track_changed_callback = handler; +} #ifndef SIMULATOR +/* Send callback events to notify about removing old tracks. */ +static void generate_unbuffer_events(void) +{ + int i; + int event_count = 0; + int numentries = MAX_TRACK_ENTRIES - num_tracks_in_memory(); + int cur_idx = track_write_idx; + + for (i = 0; i < numentries; i++) + { + if (trackdata[cur_idx].event_sent) + event_count++; + + cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; + } + + cur_idx = track_write_idx; + + for (i = 0; i < numentries; i++) + { + /* Send an event to notify that track has finished. */ + if (trackdata[cur_idx].event_sent) + { + event_count--; + if (track_unbuffer_callback) + track_unbuffer_callback(&trackdata[cur_idx].id3, + event_count == 0); + trackdata[cur_idx].event_sent = false; + } + cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; + } +} + +/* Send callback events to notify about new tracks. */ +static void generate_postbuffer_events(void) +{ + int i; + int event_count = 0; + int numentries = num_tracks_in_memory(); + int cur_idx = track_read_idx; + + for (i = 0; i < numentries; i++) + { + if (!trackdata[cur_idx].event_sent) + event_count++; + + cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; + } + + cur_idx = track_read_idx; + + for (i = 0; i < numentries; i++) + { + if (!trackdata[cur_idx].event_sent) + { + event_count--; + if (track_buffer_callback) + track_buffer_callback(&trackdata[cur_idx].id3, + event_count == 0); + trackdata[cur_idx].event_sent = true; + } + cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; + } +} + static void recalculate_watermark(int bitrate) { int bytes_per_sec; @@ -684,7 +774,7 @@ static void transfer_end(unsigned char** ppbuf, int* psize) if(!filling && unplayed_space_left < low_watermark) { filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); + queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); } if(unplayed_space_left) @@ -862,6 +952,7 @@ static void stop_playing(void) close(mpeg_file); mpeg_file = -1; remove_all_tags(); + generate_unbuffer_events(); reset_mp3_buffer(); } @@ -894,6 +985,8 @@ static void track_change(void) if (num_tracks_in_memory() > 0) { remove_current_tag(); + if (track_changed_callback) + track_changed_callback(audio_current_track()); update_playlist(); } @@ -935,9 +1028,15 @@ static void start_playback_if_ready(void) !filling || dma_underrun) { DEBUGF("P\n"); - play_pending = false; + if (play_pending) /* don't do this when recovering from DMA underrun */ + { + generate_postbuffer_events(); /* signal first track as buffered */ + if (track_changed_callback) + track_changed_callback(audio_current_track()); + play_pending = false; + } playing = true; - + last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); dma_underrun = false; @@ -1066,6 +1165,7 @@ static void mpeg_thread(void) reset_mp3_buffer(); remove_all_tags(); + generate_unbuffer_events(); if(mpeg_file >= 0) close(mpeg_file); @@ -1170,7 +1270,7 @@ static void mpeg_thread(void) /* should we start reading more data? */ if(!filling && (unplayed_space_left < low_watermark)) { filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); + queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); play_pending = true; } else if(unswapped_space_left && unswapped_space_left > unplayed_space_left) { @@ -1194,6 +1294,7 @@ static void mpeg_thread(void) reset_mp3_buffer(); remove_all_tags(); + generate_unbuffer_events(); /* Open the next file */ if (mpeg_file >= 0) @@ -1233,6 +1334,7 @@ static void mpeg_thread(void) reset_mp3_buffer(); remove_all_tags(); + generate_unbuffer_events(); /* Open the next file */ if (mpeg_file >= 0) @@ -1324,7 +1426,7 @@ static void mpeg_thread(void) { /* We need to load more data before starting */ filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); + queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); play_pending = true; } else @@ -1348,6 +1450,7 @@ static void mpeg_thread(void) /* We have to reload the current track */ close(mpeg_file); remove_all_non_current_tags(); + generate_unbuffer_events(); mpeg_file = -1; } @@ -1396,6 +1499,7 @@ static void mpeg_thread(void) close(mpeg_file); remove_all_non_current_tags(); + generate_unbuffer_events(); mpeg_file = -1; reload_track = true; } @@ -1407,8 +1511,8 @@ static void mpeg_thread(void) if(reload_track && new_file(1) >= 0) { /* Tell ourselves that we want more data */ - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); filling = true; + queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); } break; @@ -1425,12 +1529,16 @@ static void mpeg_thread(void) /* Make sure that we don't fill the entire buffer */ free_space_left -= MPEG_HIGH_WATER; + + if (ev.data == GENERATE_UNBUFFER_EVENTS) + generate_unbuffer_events(); /* do we have any more buffer space to fill? */ if(free_space_left <= 0) { DEBUGF("0\n"); filling = false; + generate_postbuffer_events(); ata_sleep(); break; } @@ -1575,7 +1683,7 @@ static void mpeg_thread(void) if (playing) playlist_update_resume_info(audio_current_track()); break; - } + } #if CONFIG_HWCODEC == MAS3587F } else @@ -2673,6 +2781,9 @@ static void mpeg_thread(void) void audio_init(void) { mpeg_errno = 0; + track_buffer_callback = NULL; + track_unbuffer_callback = NULL; + track_changed_callback = NULL; #ifndef SIMULATOR audiobuflen = audiobufend - audiobuf; -- cgit v1.2.3