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>
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>
*: ""

View file

@ -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 @@ static void init(void)
}
#endif
ata_idle_notify_init();
rc = ata_init();
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;
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 @@ static void codec_thread(void)
/* --- 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 @@ static bool audio_load_track(int offset, bool start_play)
{
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 @@ static int audio_check_new_track(void)
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 @@ static void audio_finalise_track_change(void)
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());

View file

@ -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 @@ void voice_wait(void);
#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

View file

@ -183,7 +183,10 @@ static void add_to_cache(unsigned long play_length)
} 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 @@ int scrobbler_init(void)
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 @@ void scrobbler_shutdown(void)
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;
}
}

View file

@ -601,25 +601,7 @@ int settings_save( void )
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)

View file

@ -924,14 +924,9 @@ void tagtree_init(void)
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)

View file

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

View file

@ -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 @@ bool call_ata_idle_notifys(bool force)
}
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

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__
#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

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 "id3.h"
#include "events.h"
#define MPEG_SWAP_CHUNKSIZE 0x2000
#define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we

View file

@ -100,7 +100,6 @@ struct trackdata
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_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) = 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 @@ unsigned long mpeg_get_last_header(void)
#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 @@ static void generate_unbuffer_events(void)
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 @@ static void generate_postbuffer_events(void)
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 @@ static void track_change(void)
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 @@ static void start_playback_if_ready(void)
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;
}