Implement the playback event handling as a system-wide multi-purpose event system. Unified mpeg.c and playback.c audio event handling. Converted ata_idle_notify to use the new event handling system also.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16682 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 3911223..e5df04a 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -8191,29 +8191,27 @@
</phrase>
<phrase>
id: LANG_SETTINGS_SAVE_FAILED
- desc: displayed if save settings has failed
+ desc: DEPRECATED
user:
<source>
- *: "Save Failed"
+ *: ""
</source>
<dest>
- *: "Save Failed"
+ *: ""
</dest>
<voice>
- *: "Save Failed"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_SETTINGS_PARTITION
- desc: if save settings has failed
+ desc: DEPRECATED
user:
<source>
- *: "No partition?"
- player: "Partition?"
+ *: ""
</source>
<dest>
- *: "No partition?"
- player: "Partition?"
+ *: ""
</dest>
<voice>
*: ""
diff --git a/apps/main.c b/apps/main.c
index 5985975..5dd92e5 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -19,7 +19,6 @@
#include "config.h"
#include "ata.h"
-#include "ata_idle_notify.h"
#include "disk.h"
#include "fat.h"
#include "lcd.h"
@@ -428,7 +427,6 @@
}
#endif
- ata_idle_notify_init();
rc = ata_init();
if(rc)
{
diff --git a/apps/playback.c b/apps/playback.c
index b36f68f..ee1787e 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -245,13 +245,6 @@
*/
static bool codec_requested_stop = false;
-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-) */
/* Multiple threads */
@@ -1447,51 +1440,6 @@
/* --- 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);
@@ -1783,7 +1731,7 @@
{
if (get_metadata(&id3, fd, trackname))
{
- send_event(PLAYBACK_EVENT_TRACK_BUFFER, &id3);
+ send_event(PLAYBACK_EVENT_TRACK_BUFFER, false, &id3);
tracks[track_widx].id3_hid =
bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
@@ -2020,7 +1968,7 @@
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);
+ send_event(PLAYBACK_EVENT_TRACK_FINISH, false, &curtrack_id3);
if (dir_skip)
{
@@ -2391,7 +2339,7 @@
bufgetid3(prev_ti->id3_hid)->elapsed = 0;
}
- send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3);
+ send_event(PLAYBACK_EVENT_TRACK_CHANGE, false, &curtrack_id3);
track_changed = true;
playlist_update_resume_info(audio_current_track());
diff --git a/apps/playback.h b/apps/playback.h
index 14ba35c..0b78eb3 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -24,6 +24,7 @@
#include "id3.h"
#include "mp3data.h"
+#include "events.h"
#define CODEC_IDX_AUDIO 0
#define CODEC_IDX_VOICE 1
@@ -39,13 +40,6 @@
#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 voice_wait(void);
@@ -53,13 +47,7 @@
#if CONFIG_CODEC == SWCODEC /* This #ifdef is better here than gui/gwps.c */
extern void audio_next_dir(void);
extern void audio_prev_dir(void);
-void playback_add_event(enum PLAYBACK_EVENT_TYPE type, void (*handler));
-void playback_remove_event(enum PLAYBACK_EVENT_TYPE type, void (*handler));
#else
-/* Really, should get rid of these HWCODEC api definitions here. */
-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));
# define audio_next_dir()
#define audio_prev_dir()
#endif
diff --git a/apps/scrobbler.c b/apps/scrobbler.c
index 16869bf..2f60e85 100644
--- a/apps/scrobbler.c
+++ b/apps/scrobbler.c
@@ -183,7 +183,10 @@
} else {
cache_pos++;
if (!scrobbler_ata_callback)
- scrobbler_ata_callback = register_ata_idle_func(scrobbler_flush_callback);
+ {
+ register_ata_idle_func(scrobbler_flush_callback);
+ scrobbler_ata_callback = true;
+ }
}
}
@@ -224,11 +227,7 @@
scrobbler_cache = buffer_alloc(SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
-#if CONFIG_CODEC == SWCODEC
- playback_add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
-#else
- audio_set_track_changed_event(&scrobbler_change_event);
-#endif
+ add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
cache_pos = 0;
pending = false;
scrobbler_initialised = true;
@@ -263,11 +262,7 @@
if (scrobbler_initialised)
{
-#if CONFIG_CODEC == SWCODEC
- playback_remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
-#else
- audio_set_track_changed_event(NULL);
-#endif
+ remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
scrobbler_initialised = false;
}
}
diff --git a/apps/settings.c b/apps/settings.c
index 27832b4..7eec15b 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -601,25 +601,7 @@
target doesnt have rtc ram */
write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
#endif
- if(!register_ata_idle_func(flush_config_block_callback))
- {
- int i;
- FOR_NB_SCREENS(i)
- {
- screens[i].clear_display();
-#ifdef HAVE_LCD_CHARCELLS
- screens[i].puts(0, 0, str(LANG_SETTINGS_SAVE_FAILED));
- screens[i].puts(0, 1, str(LANG_SETTINGS_PARTITION));
-#else
- screens[i].puts(4, 2, str(LANG_SETTINGS_SAVE_FAILED));
- screens[i].puts(2, 4, str(LANG_SETTINGS_PARTITION));
- screens[i].update();
-#endif
- }
- cond_talk_ids_fq(LANG_SETTINGS_SAVE_FAILED);
- sleep(HZ*2);
- return -1;
- }
+ register_ata_idle_func(flush_config_block_callback);
return 0;
}
bool settings_save_config(int options)
diff --git a/apps/tagtree.c b/apps/tagtree.c
index c5e3ebf..4572204 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -924,14 +924,9 @@
root_menu = 0;
uniqbuf = buffer_alloc(UNIQBUF_SIZE);
-#if CONFIG_CODEC == SWCODEC
- playback_add_event(PLAYBACK_EVENT_TRACK_BUFFER, tagtree_buffer_event);
- playback_add_event(PLAYBACK_EVENT_TRACK_FINISH, tagtree_track_finish_event);
-#else
- audio_set_track_buffer_event(tagtree_buffer_event);
- audio_set_track_unbuffer_event(tagtree_track_finish_event);
-#endif
-
+
+ add_event(PLAYBACK_EVENT_TRACK_BUFFER, tagtree_buffer_event);
+ add_event(PLAYBACK_EVENT_TRACK_FINISH, tagtree_track_finish_event);
}
static bool show_search_progress(bool init, int count)
diff --git a/firmware/SOURCES b/firmware/SOURCES
index b5906d4..ea8ce46 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1,4 +1,5 @@
ata_idle_notify.c
+events.c
backlight.c
buffer.c
id3.c
diff --git a/firmware/ata_idle_notify.c b/firmware/ata_idle_notify.c
index 1fc6605..a97c353 100644
--- a/firmware/ata_idle_notify.c
+++ b/firmware/ata_idle_notify.c
@@ -23,60 +23,31 @@
#include "kernel.h"
#include "string.h"
-#if USING_ATA_CALLBACK
-static ata_idle_notify ata_idle_notify_funcs[MAX_ATA_CALLBACKS];
-static int ata_callback_count = 0;
-#endif
-
-
-bool register_ata_idle_func(ata_idle_notify function)
+void register_ata_idle_func(ata_idle_notify function)
{
#if USING_ATA_CALLBACK
- int i;
- if (ata_callback_count >= MAX_ATA_CALLBACKS)
- return false;
- for (i=0; i<MAX_ATA_CALLBACKS; i++)
- {
- if (ata_idle_notify_funcs[i] == NULL)
- {
- ata_idle_notify_funcs[i] = function;
- ata_callback_count++;
- return true;
- }
- else if (ata_idle_notify_funcs[i] == function)
- return true;
- }
- return false;
+ add_event(DISK_EVENT_SPINUP, function);
#else
function(); /* just call the function now */
/* this _may_ cause problems later if the calling function
sets a variable expecting the callback to unset it, because
the callback will be run before this function exits, so before the var is set */
- return true;
#endif
}
#if USING_ATA_CALLBACK
void unregister_ata_idle_func(ata_idle_notify func, bool run)
{
- int i;
- for (i=0; i<MAX_ATA_CALLBACKS; i++)
- {
- if (ata_idle_notify_funcs[i] == func)
- {
- ata_idle_notify_funcs[i] = NULL;
- ata_callback_count--;
- if (run) func();
- }
- }
- return;
+ remove_event(DISK_EVENT_SPINUP, func);
+
+ if (run)
+ func();
}
bool call_ata_idle_notifys(bool force)
{
- int i;
static int lock_until = 0;
- ata_idle_notify function;
+
if (!force)
{
if (TIME_BEFORE(current_tick,lock_until) )
@@ -84,22 +55,8 @@
}
lock_until = current_tick + 30*HZ;
- for (i = 0; i < MAX_ATA_CALLBACKS; i++)
- {
- if (ata_idle_notify_funcs[i])
- {
- function = ata_idle_notify_funcs[i];
- ata_idle_notify_funcs[i] = NULL;
- function();
- ata_callback_count--;
- }
- }
+ send_event(DISK_EVENT_SPINUP, true, NULL);
+
return true;
}
-
-void ata_idle_notify_init(void)
-{
- ata_callback_count = 0;
- memset(ata_idle_notify_funcs, 0, sizeof(ata_idle_notify_funcs));
-}
#endif
diff --git a/firmware/events.c b/firmware/events.c
new file mode 100644
index 0000000..eaf2e5c
--- /dev/null
+++ b/firmware/events.c
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2008 by Miika Pekkarinen
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include "events.h"
+#include "panic.h"
+
+struct sysevent {
+ unsigned short id;
+ void (*callback)(void *data);
+};
+
+struct sysevent events[MAX_SYS_EVENTS];
+
+bool add_event(unsigned short id, void (*handler))
+{
+ int i;
+
+ /* Chcek if the event already exists. */
+ for (i = 0; i < MAX_SYS_EVENTS; i++)
+ {
+ if (events[i].callback == handler && events[i].id == id)
+ return false;
+ }
+
+ /* Try to find a free slot. */
+ for (i = 0; i < MAX_SYS_EVENTS; i++)
+ {
+ if (events[i].callback == NULL)
+ {
+ events[i].id = id;
+ events[i].callback = handler;
+ return true;
+ }
+ }
+
+ panicf("event line full");
+ return false;
+}
+
+void remove_event(unsigned short id, void (*handler))
+{
+ int i;
+
+ for (i = 0; i < MAX_SYS_EVENTS; i++)
+ {
+ if (events[i].id == id && events[i].callback == handler)
+ {
+ events[i].callback = NULL;
+ return;
+ }
+ }
+
+ panicf("event not found");
+}
+
+void send_event(unsigned short id, bool oneshot, void *data)
+{
+ int i;
+
+ for (i = 0; i < MAX_SYS_EVENTS; i++)
+ {
+ if (events[i].id == id && events[i].callback != NULL)
+ {
+ events[i].callback(data);
+
+ if (oneshot)
+ events[i].callback = NULL;
+ }
+ }
+}
+
diff --git a/firmware/export/ata_idle_notify.h b/firmware/export/ata_idle_notify.h
index ee825c9..1dda3e1 100644
--- a/firmware/export/ata_idle_notify.h
+++ b/firmware/export/ata_idle_notify.h
@@ -19,7 +19,9 @@
#ifndef __ATACALLBACK_H__
#define __ATACALLBACK_H__
+
#include <stdbool.h>
+#include "events.h"
#if 0
NOTE: ata_idle_nofity usage notes..
@@ -34,15 +36,17 @@
5) Dont Panic!
#endif
+enum {
+ DISK_EVENT_SPINUP = (EVENT_CLASS_DISK|1),
+};
+
#define USING_ATA_CALLBACK !defined(SIMULATOR) \
&& !defined(HAVE_FLASH_DISK)
-#define MAX_ATA_CALLBACKS 5
typedef bool (*ata_idle_notify)(void);
-extern bool register_ata_idle_func(ata_idle_notify function);
+extern void register_ata_idle_func(ata_idle_notify function);
#if USING_ATA_CALLBACK
-extern void ata_idle_notify_init(void);
extern void unregister_ata_idle_func(ata_idle_notify function, bool run);
extern bool call_ata_idle_notifys(bool force);
#else
diff --git a/firmware/export/events.h b/firmware/export/events.h
new file mode 100644
index 0000000..b27b5de
--- /dev/null
+++ b/firmware/export/events.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2008 by Miika Pekkarinen
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _EVENTS_H
+#define _EVENTS_H
+
+#include <stdbool.h>
+
+#define MAX_SYS_EVENTS 10
+
+/**
+ * High nibble = Event class definition
+ * Low nibble = Event ID
+ */
+
+#define EVENT_CLASS_DISK 0x0100
+#define EVENT_CLASS_PLAYBACK 0x0200
+
+/**
+ * Because same playback events are used in mpeg.c and playback.c, define
+ * them here to prevent cluttering and ifdefs.
+ */
+enum {
+ PLAYBACK_EVENT_TRACK_BUFFER = (EVENT_CLASS_PLAYBACK|1),
+ PLAYBACK_EVENT_TRACK_FINISH,
+ PLAYBACK_EVENT_TRACK_CHANGE,
+};
+
+
+bool add_event(unsigned short id, void (*handler));
+void remove_event(unsigned short id, void (*handler));
+void send_event(unsigned short id, bool oneshot, void *data);
+
+#endif
+
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h
index 3e36c44..0a9d62c 100644
--- a/firmware/export/mpeg.h
+++ b/firmware/export/mpeg.h
@@ -21,6 +21,7 @@
#include <stdbool.h>
#include "id3.h"
+#include "events.h"
#define MPEG_SWAP_CHUNKSIZE 0x2000
#define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 693e2df..9023c30 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -100,7 +100,6 @@
struct mp3entry id3;
int mempos;
int load_ahead_index;
- bool event_sent;
};
static struct trackdata trackdata[MAX_TRACK_ENTRIES];
@@ -116,11 +115,6 @@
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) = NULL;
-void (*track_buffer_callback)(struct mp3entry *id3) = NULL;
-void (*track_unbuffer_callback)(struct mp3entry *id3) = NULL;
-
/* Cuesheet callback */
static bool (*cuesheet_callback)(const char *filename) = NULL;
@@ -475,21 +469,6 @@
#endif /* !SIMULATOR */
}
-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;
-}
-
void audio_set_cuesheet_callback(bool (*handler)(const char *filename))
{
cuesheet_callback = handler;
@@ -506,12 +485,7 @@
for (i = 0; i < numentries; i++)
{
/* Send an event to notify that track has finished. */
- if (trackdata[cur_idx].event_sent)
- {
- if (track_unbuffer_callback)
- track_unbuffer_callback(&trackdata[cur_idx].id3);
- trackdata[cur_idx].event_sent = false;
- }
+ send_event(PLAYBACK_EVENT_TRACK_FINISH, false, &trackdata[cur_idx].id3);
cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
}
}
@@ -525,12 +499,7 @@
for (i = 0; i < numentries; i++)
{
- if (!trackdata[cur_idx].event_sent)
- {
- if (track_buffer_callback)
- track_buffer_callback(&trackdata[cur_idx].id3);
- trackdata[cur_idx].event_sent = true;
- }
+ send_event(PLAYBACK_EVENT_TRACK_BUFFER, false, &trackdata[cur_idx].id3);
cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
}
}
@@ -1080,8 +1049,7 @@
if (num_tracks_in_memory() > 0)
{
remove_current_tag();
- if (track_changed_callback)
- track_changed_callback(audio_current_track());
+ send_event(PLAYBACK_EVENT_TRACK_CHANGE, false, audio_current_track());
update_playlist();
}
@@ -1134,8 +1102,7 @@
if (play_pending_track_change)
{
play_pending_track_change = false;
- if(track_changed_callback)
- track_changed_callback(audio_current_track());
+ send_event(PLAYBACK_EVENT_TRACK_CHANGE, false, audio_current_track());
}
play_pending = false;
}