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
This commit is contained in:
Miika Pekkarinen 2008-03-16 13:55:16 +00:00
parent 478ba0afa1
commit 19c6e66c13
14 changed files with 182 additions and 209 deletions

View file

@ -8191,29 +8191,27 @@
</phrase> </phrase>
<phrase> <phrase>
id: LANG_SETTINGS_SAVE_FAILED id: LANG_SETTINGS_SAVE_FAILED
desc: displayed if save settings has failed desc: DEPRECATED
user: user:
<source> <source>
*: "Save Failed" *: ""
</source> </source>
<dest> <dest>
*: "Save Failed" *: ""
</dest> </dest>
<voice> <voice>
*: "Save Failed" *: ""
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
id: LANG_SETTINGS_PARTITION id: LANG_SETTINGS_PARTITION
desc: if save settings has failed desc: DEPRECATED
user: user:
<source> <source>
*: "No partition?" *: ""
player: "Partition?"
</source> </source>
<dest> <dest>
*: "No partition?" *: ""
player: "Partition?"
</dest> </dest>
<voice> <voice>
*: "" *: ""

View file

@ -19,7 +19,6 @@
#include "config.h" #include "config.h"
#include "ata.h" #include "ata.h"
#include "ata_idle_notify.h"
#include "disk.h" #include "disk.h"
#include "fat.h" #include "fat.h"
#include "lcd.h" #include "lcd.h"
@ -428,7 +427,6 @@ static void init(void)
} }
#endif #endif
ata_idle_notify_init();
rc = ata_init(); rc = ata_init();
if(rc) if(rc)
{ {

View file

@ -245,13 +245,6 @@ 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;
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-) */ static size_t buffer_margin = 0; /* Buffer margin aka anti-skip buffer (A/C-) */
/* Multiple threads */ /* Multiple threads */
@ -1447,51 +1440,6 @@ 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);
@ -1783,7 +1731,7 @@ static bool audio_load_track(int offset, bool start_play)
{ {
if (get_metadata(&id3, fd, trackname)) 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 = tracks[track_widx].id3_hid =
bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3); bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3);
@ -2020,7 +1968,7 @@ static int audio_check_new_track(void)
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. */ /* 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) if (dir_skip)
{ {
@ -2391,7 +2339,7 @@ static void audio_finalise_track_change(void)
bufgetid3(prev_ti->id3_hid)->elapsed = 0; 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; track_changed = true;
playlist_update_resume_info(audio_current_track()); playlist_update_resume_info(audio_current_track());

View file

@ -24,6 +24,7 @@
#include "id3.h" #include "id3.h"
#include "mp3data.h" #include "mp3data.h"
#include "events.h"
#define CODEC_IDX_AUDIO 0 #define CODEC_IDX_AUDIO 0
#define CODEC_IDX_VOICE 1 #define CODEC_IDX_VOICE 1
@ -39,13 +40,6 @@
#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 voice_wait(void); void voice_wait(void);
@ -53,13 +47,7 @@ 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 */
extern void audio_next_dir(void); extern void audio_next_dir(void);
extern void audio_prev_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 #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_next_dir()
#define audio_prev_dir() #define audio_prev_dir()
#endif #endif

View file

@ -183,7 +183,10 @@ static void add_to_cache(unsigned long play_length)
} else { } else {
cache_pos++; cache_pos++;
if (!scrobbler_ata_callback) 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 @@ int scrobbler_init(void)
scrobbler_cache = buffer_alloc(SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN); scrobbler_cache = buffer_alloc(SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
#if CONFIG_CODEC == SWCODEC add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
playback_add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
#else
audio_set_track_changed_event(&scrobbler_change_event);
#endif
cache_pos = 0; cache_pos = 0;
pending = false; pending = false;
scrobbler_initialised = true; scrobbler_initialised = true;
@ -263,11 +262,7 @@ void scrobbler_shutdown(void)
if (scrobbler_initialised) if (scrobbler_initialised)
{ {
#if CONFIG_CODEC == SWCODEC remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
playback_remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
#else
audio_set_track_changed_event(NULL);
#endif
scrobbler_initialised = false; scrobbler_initialised = false;
} }
} }

View file

@ -601,25 +601,7 @@ int settings_save( void )
target doesnt have rtc ram */ target doesnt have rtc ram */
write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE); write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
#endif #endif
if(!register_ata_idle_func(flush_config_block_callback)) 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;
}
return 0; return 0;
} }
bool settings_save_config(int options) bool settings_save_config(int options)

View file

@ -924,14 +924,9 @@ void tagtree_init(void)
root_menu = 0; root_menu = 0;
uniqbuf = buffer_alloc(UNIQBUF_SIZE); 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) static bool show_search_progress(bool init, int count)

View file

@ -1,4 +1,5 @@
ata_idle_notify.c ata_idle_notify.c
events.c
backlight.c backlight.c
buffer.c buffer.c
id3.c id3.c

View file

@ -23,60 +23,31 @@
#include "kernel.h" #include "kernel.h"
#include "string.h" #include "string.h"
#if USING_ATA_CALLBACK void register_ata_idle_func(ata_idle_notify function)
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)
{ {
#if USING_ATA_CALLBACK #if USING_ATA_CALLBACK
int i; add_event(DISK_EVENT_SPINUP, function);
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;
#else #else
function(); /* just call the function now */ function(); /* just call the function now */
/* this _may_ cause problems later if the calling function /* this _may_ cause problems later if the calling function
sets a variable expecting the callback to unset it, because 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 */ the callback will be run before this function exits, so before the var is set */
return true;
#endif #endif
} }
#if USING_ATA_CALLBACK #if USING_ATA_CALLBACK
void unregister_ata_idle_func(ata_idle_notify func, bool run) void unregister_ata_idle_func(ata_idle_notify func, bool run)
{ {
int i; remove_event(DISK_EVENT_SPINUP, func);
for (i=0; i<MAX_ATA_CALLBACKS; i++)
{ if (run)
if (ata_idle_notify_funcs[i] == func) func();
{
ata_idle_notify_funcs[i] = NULL;
ata_callback_count--;
if (run) func();
}
}
return;
} }
bool call_ata_idle_notifys(bool force) bool call_ata_idle_notifys(bool force)
{ {
int i;
static int lock_until = 0; static int lock_until = 0;
ata_idle_notify function;
if (!force) if (!force)
{ {
if (TIME_BEFORE(current_tick,lock_until) ) if (TIME_BEFORE(current_tick,lock_until) )
@ -84,22 +55,8 @@ bool call_ata_idle_notifys(bool force)
} }
lock_until = current_tick + 30*HZ; lock_until = current_tick + 30*HZ;
for (i = 0; i < MAX_ATA_CALLBACKS; i++) send_event(DISK_EVENT_SPINUP, true, NULL);
{
if (ata_idle_notify_funcs[i])
{
function = ata_idle_notify_funcs[i];
ata_idle_notify_funcs[i] = NULL;
function();
ata_callback_count--;
}
}
return true; return true;
} }
void ata_idle_notify_init(void)
{
ata_callback_count = 0;
memset(ata_idle_notify_funcs, 0, sizeof(ata_idle_notify_funcs));
}
#endif #endif

88
firmware/events.c Normal file
View file

@ -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;
}
}
}

View file

@ -19,7 +19,9 @@
#ifndef __ATACALLBACK_H__ #ifndef __ATACALLBACK_H__
#define __ATACALLBACK_H__ #define __ATACALLBACK_H__
#include <stdbool.h> #include <stdbool.h>
#include "events.h"
#if 0 #if 0
NOTE: ata_idle_nofity usage notes.. NOTE: ata_idle_nofity usage notes..
@ -34,15 +36,17 @@
5) Dont Panic! 5) Dont Panic!
#endif #endif
enum {
DISK_EVENT_SPINUP = (EVENT_CLASS_DISK|1),
};
#define USING_ATA_CALLBACK !defined(SIMULATOR) \ #define USING_ATA_CALLBACK !defined(SIMULATOR) \
&& !defined(HAVE_FLASH_DISK) && !defined(HAVE_FLASH_DISK)
#define MAX_ATA_CALLBACKS 5
typedef bool (*ata_idle_notify)(void); 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 #if USING_ATA_CALLBACK
extern void ata_idle_notify_init(void);
extern void unregister_ata_idle_func(ata_idle_notify function, bool run); extern void unregister_ata_idle_func(ata_idle_notify function, bool run);
extern bool call_ata_idle_notifys(bool force); extern bool call_ata_idle_notifys(bool force);
#else #else

51
firmware/export/events.h Normal file
View file

@ -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

View file

@ -21,6 +21,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "id3.h" #include "id3.h"
#include "events.h"
#define MPEG_SWAP_CHUNKSIZE 0x2000 #define MPEG_SWAP_CHUNKSIZE 0x2000
#define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we #define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we

View file

@ -100,7 +100,6 @@ struct trackdata
struct mp3entry id3; struct mp3entry id3;
int mempos; int mempos;
int load_ahead_index; int load_ahead_index;
bool event_sent;
}; };
static struct trackdata trackdata[MAX_TRACK_ENTRIES]; static struct trackdata trackdata[MAX_TRACK_ENTRIES];
@ -116,11 +115,6 @@ static int track_read_idx = 0;
static int track_write_idx = 0; static int track_write_idx = 0;
#endif /* !SIMULATOR */ #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 */ /* Cuesheet callback */
static bool (*cuesheet_callback)(const char *filename) = NULL; static bool (*cuesheet_callback)(const char *filename) = NULL;
@ -475,21 +469,6 @@ unsigned long mpeg_get_last_header(void)
#endif /* !SIMULATOR */ #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)) void audio_set_cuesheet_callback(bool (*handler)(const char *filename))
{ {
cuesheet_callback = handler; cuesheet_callback = handler;
@ -506,12 +485,7 @@ static void generate_unbuffer_events(void)
for (i = 0; i < numentries; i++) for (i = 0; i < numentries; i++)
{ {
/* Send an event to notify that track has finished. */ /* Send an event to notify that track has finished. */
if (trackdata[cur_idx].event_sent) send_event(PLAYBACK_EVENT_TRACK_FINISH, false, &trackdata[cur_idx].id3);
{
if (track_unbuffer_callback)
track_unbuffer_callback(&trackdata[cur_idx].id3);
trackdata[cur_idx].event_sent = false;
}
cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
} }
} }
@ -525,12 +499,7 @@ static void generate_postbuffer_events(void)
for (i = 0; i < numentries; i++) for (i = 0; i < numentries; i++)
{ {
if (!trackdata[cur_idx].event_sent) send_event(PLAYBACK_EVENT_TRACK_BUFFER, false, &trackdata[cur_idx].id3);
{
if (track_buffer_callback)
track_buffer_callback(&trackdata[cur_idx].id3);
trackdata[cur_idx].event_sent = true;
}
cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
} }
} }
@ -1080,8 +1049,7 @@ static void track_change(void)
if (num_tracks_in_memory() > 0) if (num_tracks_in_memory() > 0)
{ {
remove_current_tag(); remove_current_tag();
if (track_changed_callback) send_event(PLAYBACK_EVENT_TRACK_CHANGE, false, audio_current_track());
track_changed_callback(audio_current_track());
update_playlist(); update_playlist();
} }
@ -1134,8 +1102,7 @@ static void start_playback_if_ready(void)
if (play_pending_track_change) if (play_pending_track_change)
{ {
play_pending_track_change = false; play_pending_track_change = false;
if(track_changed_callback) send_event(PLAYBACK_EVENT_TRACK_CHANGE, false, audio_current_track());
track_changed_callback(audio_current_track());
} }
play_pending = false; play_pending = false;
} }