Get rid of some superfluous single-purpose functions in playback.

* Remove explicit tracking of elapsed time of previous track.
* Remove function to obtain auto skip flag.
* Most playback events now carry the extra information instead and
  pass 'struct track_event *' for data.
* Tweak scrobbler to use PLAYBACK_EVENT_TRACK_FINISH, which makes
  it cleaner and removes the struct mp3entry.

Change-Id: I500d2abb4056a32646496efc3617406e36811ec5
This commit is contained in:
Michael Sevakis 2013-07-12 12:06:38 -04:00
parent ffa8626b0c
commit 023f6b6efd
14 changed files with 236 additions and 242 deletions

View file

@ -31,21 +31,29 @@
/** Playback events **/
enum {
/* Playback is starting from a stopped state */
/* Playback is starting from a stopped state
data = NULL */
PLAYBACK_EVENT_START_PLAYBACK = (EVENT_CLASS_PLAYBACK|1),
/* Audio has begun buffering for decoding track (or is already completed) */
/* Audio has begun buffering for decoding track (or is already completed)
data = &(struct track_event){} */
PLAYBACK_EVENT_TRACK_BUFFER,
/* Handles for current user track are ready (other than audio or codec) */
/* Handles for current user track are ready (other than audio or codec)
data = &(struct track_event){} */
PLAYBACK_EVENT_CUR_TRACK_READY,
/* Current user track finished */
/* Current user track finished
data = &(struct track_event){} */
PLAYBACK_EVENT_TRACK_FINISH,
/* A new current user track has begun */
/* A new current user track has begun
data = &(struct track_event){} */
PLAYBACK_EVENT_TRACK_CHANGE,
/* A manual skip is about to be processed */
/* A manual skip is about to be processed
data = NULL */
PLAYBACK_EVENT_TRACK_SKIP,
/* Next track medadata was just loaded */
/* Next track medadata was just loaded
data = &(struct track_event){} */
PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
/* Voice is playing: data = &(bool){true|false} */
/* Voice is playing
data = &(bool){true|false} */
PLAYBACK_EVENT_VOICE_PLAYING,
};

View file

@ -1190,7 +1190,7 @@ long gui_wps_show(void)
static void track_changed_callback(void *param)
{
struct wps_state *state = skin_get_global_state();
state->id3 = (struct mp3entry*)param;
state->id3 = ((struct track_event *)param)->id3;
state->nid3 = audio_next_track();
if (state->id3->cuesheet)
{

View file

@ -46,7 +46,7 @@ static const struct dim dim = { .width = 200, .height = 200 };
* notify about track change, and show track info */
static void track_changed_callback(void *param)
{
struct mp3entry* id3 = (struct mp3entry*)param;
struct mp3entry* id3 = ((struct track_event *)param)->id3;
JNIEnv e = *env_ptr;
if (id3)
{
@ -108,7 +108,9 @@ static void track_changed_callback(void *param)
* notify about track finishing */
static void track_finished_callback(void *param)
{
(void)param;
if (((struct track_event *)param)->flags & TEF_REWIND)
return; /* Not a true track end */
JNIEnv e = *env_ptr;
e->CallVoidMethod(env_ptr, NotificationManager_instance,
finishNotification);

View file

@ -420,6 +420,7 @@ static void init(void)
global_settings.superbass);
#endif /* CONFIG_CODEC != SWCODEC */
if (global_settings.audioscrobbler)
scrobbler_init();
audio_init();
@ -700,7 +701,10 @@ static void init(void)
playlist_init();
tree_mem_init();
filetype_init();
if (global_settings.audioscrobbler)
scrobbler_init();
shortcuts_init();
#if CONFIG_CODEC != SWCODEC

View file

@ -157,7 +157,7 @@ static int audioscrobbler_callback(int action,const struct menu_item_ex *this_it
scrobbler_init();
if(scrobbler_is_enabled() && !global_settings.audioscrobbler)
scrobbler_shutdown();
scrobbler_shutdown(false);
break;
}
return action;

View file

@ -269,8 +269,6 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter)
{
long msg_id = -1;
scrobbler_poweroff();
#if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
if(!charger_inserted())
#endif
@ -349,6 +347,7 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter)
#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
audio_close_recording();
#endif
scrobbler_shutdown(true);
if(global_settings.talk_menu)
{

View file

@ -129,8 +129,6 @@ static unsigned int current_track_counter = 0;
#ifndef SIMULATOR
static void stop_playing(void);
/* Play time of the previous track */
static unsigned long prev_track_elapsed;
static int track_read_idx = 0;
static int track_write_idx = 0;
@ -362,7 +360,15 @@ static bool audio_dispatch_event(unsigned short event, unsigned long data)
}
return false;
}
#endif
static void send_track_event(unsigned int id, struct mp3entry *id3)
{
struct mp3entry *cur_id3 =
&trackdata[track_read_idx & MAX_TRACK_ENTRIES_MASK].id3;
unsigned int flags = id3 == cur_id3 ? TEF_CURRENT : 0;
send_event(id, &(struct track_event){ .flags = flags, .id3 = id3 });
}
#endif /* SIMULATOR */
/***********************************************************************/
@ -609,7 +615,7 @@ static void generate_unbuffer_events(void)
for (i = 0; i < numentries; i++)
{
/* Send an event to notify that track has finished. */
send_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3);
send_track_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3);
cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
}
}
@ -623,7 +629,7 @@ static void generate_postbuffer_events(void)
for (i = 0; i < numentries; i++)
{
send_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3);
send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3);
cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
}
}
@ -1006,7 +1012,7 @@ static struct trackdata *add_track_to_tag_list(const char *filename)
send_nid3_event = (track_write_idx == track_read_idx + 1);
track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK;
if (send_nid3_event)
send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL);
send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, &track->id3);
debug_tags();
return track;
}
@ -1093,17 +1099,11 @@ static int new_file(int steps)
static void stop_playing(void)
{
struct trackdata *track;
/* Stop the current stream */
mp3_play_stop();
playing = false;
filling = false;
track = get_trackdata(0);
if (track != NULL)
prev_track_elapsed = track->id3.elapsed;
if(mpeg_file >= 0)
close(mpeg_file);
mpeg_file = -1;
@ -1112,17 +1112,12 @@ static void stop_playing(void)
reset_mp3_buffer();
}
static void end_current_track(void) {
struct trackdata *track;
static void end_current_track(void)
{
play_pending = false;
playing = false;
mp3_play_pause(false);
track = get_trackdata(0);
if (track != NULL)
prev_track_elapsed = track->id3.elapsed;
reset_mp3_buffer();
remove_all_tags();
generate_unbuffer_events();
@ -1164,9 +1159,6 @@ static void track_change(void)
{
DEBUGF("Track change\n");
struct trackdata *track = get_trackdata(0);
prev_track_elapsed = track->id3.elapsed;
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
/* Reset the AVC */
sound_set_avc(-1);
@ -1177,17 +1169,15 @@ static void track_change(void)
remove_current_tag();
update_playlist();
if (is_playing)
send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track());
{
send_track_event(PLAYBACK_EVENT_TRACK_CHANGE,
audio_current_track());
}
}
current_track_counter++;
}
unsigned long audio_prev_elapsed(void)
{
return prev_track_elapsed;
}
#ifdef DEBUG
void hexdump(const unsigned char *buf, int len)
{
@ -1229,7 +1219,8 @@ static void start_playback_if_ready(void)
if (play_pending_track_change)
{
play_pending_track_change = false;
send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track());
send_track_event(PLAYBACK_EVENT_TRACK_CHANGE,
audio_current_track());
}
play_pending = false;
}
@ -2828,11 +2819,6 @@ void audio_play(long offset)
void audio_stop(void)
{
#ifndef SIMULATOR
if (playing)
{
struct trackdata *track = get_trackdata(0);
prev_track_elapsed = track->id3.elapsed;
}
mpeg_stop_done = false;
queue_post(&mpeg_queue, MPEG_STOP, 0);
while(!mpeg_stop_done)

View file

@ -155,13 +155,6 @@ static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */
/* Peeking functions can yield and mess us up */
static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/
/** For Scrobbler support **/
/* Previous track elapsed time */
static unsigned long prev_track_elapsed = 0; /* (A,O-) */
/** For album art support **/
#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT
#ifdef HAVE_ALBUMART
@ -296,9 +289,8 @@ enum track_skip_type
would work as expected */
/* Used to indicate status for the events. Must be separate to satisfy all
clients so the correct metadata is read when sending the change events
and also so that it is read correctly outside the events. */
static bool automatic_skip = false; /* (A, O-) */
clients so the correct metadata is read when sending the change events. */
static unsigned int track_event_flags = TEF_NONE; /* (A, O-) */
/* Pending manual track skip offset */
static int skip_offset = 0; /* (A, O) */
@ -1056,6 +1048,16 @@ static void audio_handle_track_load_status(int trackstat)
}
}
/* Send track events that use a struct track_event for data */
static void send_track_event(unsigned int id, unsigned int flags,
struct mp3entry *id3)
{
if (id3 == id3_get(PLAYING_ID3))
flags |= TEF_CURRENT;
send_event(id, &(struct track_event){ .flags = flags, .id3 = id3 });
}
/* Announce the end of playing the current track */
static void audio_playlist_track_finish(void)
{
@ -1066,12 +1068,8 @@ static void audio_playlist_track_finish(void)
if (id3)
{
send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
prev_track_elapsed = id3->elapsed;
}
else
{
prev_track_elapsed = 0;
send_track_event(PLAYBACK_EVENT_TRACK_FINISH,
track_event_flags, id3);
}
}
@ -1081,7 +1079,10 @@ static void audio_playlist_track_change(void)
struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3));
if (id3)
send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3);
{
send_track_event(PLAYBACK_EVENT_TRACK_CHANGE,
track_event_flags, id3);
}
position_key = pcmbuf_get_position_key();
@ -1092,8 +1093,8 @@ static void audio_playlist_track_change(void)
static void audio_update_and_announce_next_track(const struct mp3entry *id3_next)
{
id3_write_locked(NEXTTRACK_ID3, id3_next);
send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
id3_get(NEXTTRACK_ID3));
send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
0, id3_get(NEXTTRACK_ID3));
}
/* Bring the user current mp3entry up to date and set a new offset for the
@ -1441,7 +1442,7 @@ static bool audio_start_codec(bool auto_skip)
bool resume = !auto_skip;
/* Send the "buffer" event to obtain the resume position for the codec */
send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3);
send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, 0, cur_id3);
if (!resume)
{
@ -1497,7 +1498,7 @@ static bool audio_start_codec(bool auto_skip)
#endif
{
/* Send the "buffer" event now */
send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3);
send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, 0, cur_id3);
}
buf_pin_handle(info->id3_hid, false);
@ -1893,7 +1894,8 @@ static int audio_finish_load_track(struct track_info *info)
/* Send only when the track handles could not all be opened ahead of
time for the user's current track - otherwise everything is ready
by the time PLAYBACK_EVENT_TRACK_CHANGE is sent */
send_event(PLAYBACK_EVENT_CUR_TRACK_READY, id3_get(PLAYING_ID3));
send_track_event(PLAYBACK_EVENT_CUR_TRACK_READY, 0,
id3_get(PLAYING_ID3));
}
#ifdef HAVE_CODEC_BUFFERING
@ -2157,7 +2159,7 @@ static void audio_on_finish_load_track(int id3_hid)
buf_read_cuesheet(info->cuesheet_hid);
}
if (audio_start_codec(automatic_skip))
if (audio_start_codec(track_event_flags & TEF_AUTO_SKIP))
{
if (is_user_current)
{
@ -2356,7 +2358,7 @@ static void audio_on_codec_complete(int status)
int trackstat = LOAD_TRACK_OK;
automatic_skip = true;
track_event_flags = TEF_AUTO_SKIP;
skip_pending = TRACK_SKIP_AUTO;
/* Does this track have an entry allocated? */
@ -2471,7 +2473,7 @@ static void audio_start_playback(size_t offset, unsigned int flags)
halt_decoding_track(true);
automatic_skip = false;
track_event_flags = TEF_NONE;
ff_rw_mode = false;
if (flags & AUDIO_START_RESTART)
@ -2595,7 +2597,7 @@ static void audio_stop_playback(void)
audio_playlist_track_finish();
skip_pending = TRACK_SKIP_NONE;
automatic_skip = false;
track_event_flags = TEF_NONE;
/* Close all tracks and mark them NULL */
remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback);
@ -2667,7 +2669,7 @@ static void audio_on_skip(void)
ff_rw_mode = false;
/* Manual skip */
automatic_skip = false;
track_event_flags = TEF_NONE;
/* If there was an auto skip in progress, there will be residual
advancement of the playlist and/or track list so compensation will be
@ -2755,7 +2757,7 @@ static void audio_on_dir_skip(int direction)
ff_rw_mode = false;
/* Manual skip */
automatic_skip = false;
track_event_flags = TEF_NONE;
audio_playlist_track_finish();
@ -2820,14 +2822,14 @@ static void audio_on_ff_rewind(long time)
struct mp3entry *id3 = id3_get(PLAYING_ID3);
struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
automatic_skip = false;
track_event_flags = TEF_NONE;
/* Send event before clobbering the time */
/* FIXME: Nasty, but the tagtree expects this so that rewinding and
then skipping back to this track resumes properly. Something else
should be sent. We're not _really_ finishing the track are we? */
/* Send event before clobbering the time if rewinding. */
if (time == 0)
send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
{
send_track_event(PLAYBACK_EVENT_TRACK_FINISH,
track_event_flags | TEF_REWIND, id3);
}
id3->elapsed = time;
queue_reply(&audio_queue, 1);
@ -3662,14 +3664,6 @@ void playback_release_aa_slot(int slot)
}
#endif /* HAVE_ALBUMART */
/* Is an automatic skip in progress? If called outside transition callbacks,
indicates the last skip type at the time it was processed and isn't very
meaningful. */
bool audio_automatic_skip(void)
{
return automatic_skip;
}
/* Would normally calculate byte offset from an elapsed time but is not
used on SWCODEC */
int audio_get_file_pos(void)
@ -3677,12 +3671,6 @@ int audio_get_file_pos(void)
return 0;
}
/* Return the elapsed time of the track previous to the current */
unsigned long audio_prev_elapsed(void)
{
return prev_track_elapsed;
}
/* Return total file buffer length after accounting for the talk buf */
size_t audio_get_filebuflen(void)
{

View file

@ -88,10 +88,6 @@ enum
bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
size_t audio_get_filebuflen(void);
/* Automatic transition? Only valid to call during the track change events,
otherwise the result is undefined. */
bool audio_automatic_skip(void);
unsigned int playback_status(void);
#endif /* _PLAYBACK_H */

View file

@ -89,7 +89,7 @@ static int last_screen = GO_TO_ROOT; /* unfortunatly needed so we can resume
static char current_track_path[MAX_PATH];
static void rootmenu_track_changed_callback(void* param)
{
struct mp3entry *id3 = (struct mp3entry *)param;
struct mp3entry *id3 = ((struct track_event *)param)->id3;
strlcpy(current_track_path, id3->path, MAX_PATH);
}
static int browser(void* param)

View file

@ -52,50 +52,40 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging
/* longest entry I've had is 323, add a safety margin */
#define SCROBBLER_CACHE_LEN 512
static int scrobbler_cache;
static int cache_pos;
static struct mp3entry scrobbler_entry;
static bool pending = false;
static bool scrobbler_initialised = false;
static int scrobbler_cache = 0;
static int cache_pos = 0;
static bool pending = false;
#if CONFIG_RTC
static time_t timestamp;
#else
static unsigned long timestamp;
#endif
/* Crude work-around for Archos Sims - return a set amount */
#if (CONFIG_CODEC != SWCODEC) && (CONFIG_PLATFORM & PLATFORM_HOSTED)
unsigned long audio_prev_elapsed(void)
{
return 120000;
}
#endif
#define BASE_FILENAME ".scrobbler.log"
#define HDR_STR_TIMELESS
#define get_timestamp() ((long)timestamp)
#define record_timestamp() ((void)(timestamp = mktime(get_time())))
#else /* !CONFIG_RTC */
#define HDR_STR_TIMELESS " Timeless"
#define BASE_FILENAME ".scrobbler-timeless.log"
#define get_timestamp() (0l)
#define record_timestamp() ({})
#endif /* CONFIG_RTC */
static void get_scrobbler_filename(char *path, size_t size)
{
int used;
#if CONFIG_RTC
const char *base_filename = ".scrobbler.log";
#else
const char *base_filename = ".scrobbler-timeless.log";
#endif
/* Get location of USB mass storage area */
#ifdef APPLICATION
#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
used = snprintf(path, size, "/home/user/MyDocs/%s", base_filename);
used = snprintf(path, size, "/home/user/MyDocs/%s", BASE_FILENAME);
#elif (CONFIG_PLATFORM & PLATFORM_ANDROID)
used = snprintf(path, size, "/sdcard/%s", base_filename);
used = snprintf(path, size, "/sdcard/%s", BASE_FILENAME);
#elif defined (SAMSUNG_YPR0)
used = snprintf(path, size, "%s/%s", HOME_DIR, base_filename);
used = snprintf(path, size, "%s/%s", HOME_DIR, BASE_FILENAME);
#else /* SDL/unknown RaaA build */
used = snprintf(path, size, "%s/%s", ROCKBOX_DIR, base_filename);
used = snprintf(path, size, "%s/%s", ROCKBOX_DIR, BASE_FILENAME);
#endif /* (CONFIG_PLATFORM & PLATFORM_MAEMO) */
#else
used = snprintf(path, size, "/%s", base_filename);
used = snprintf(path, size, "/%s", BASE_FILENAME);
#endif
if (used >= (int)size)
@ -121,12 +111,9 @@ static void write_cache(void)
if(fd >= 0)
{
fdprintf(fd, "#AUDIOSCROBBLER/" SCROBBLER_VERSION "\n"
"#TZ/UNKNOWN\n"
#if CONFIG_RTC
"#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION "\n");
#else
"#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION " Timeless\n");
#endif
"#TZ/UNKNOWN\n" "#CLIENT/Rockbox "
TARGET_NAME SCROBBLER_REVISION
HDR_STR_TIMELESS "\n");
close(fd);
}
@ -170,51 +157,43 @@ static void scrobbler_flush_callback(void *data)
write_cache();
}
static void add_to_cache(unsigned long play_length)
static void add_to_cache(const struct mp3entry *id)
{
if ( cache_pos >= SCROBBLER_MAX_CACHE )
write_cache();
int ret;
char rating = 'S'; /* Skipped */
char* scrobbler_buf = core_get_data(scrobbler_cache);
logf("SCROBBLER: add_to_cache[%d]", cache_pos);
if ( play_length > (scrobbler_entry.length/2) )
if (id->elapsed > id->length / 2)
rating = 'L'; /* Listened */
if (scrobbler_entry.tracknum > 0)
{
ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos),
char tracknum[11] = { "" };
if (id->tracknum > 0)
snprintf(tracknum, sizeof (tracknum), "%d", id->tracknum);
int ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos),
SCROBBLER_CACHE_LEN,
"%s\t%s\t%s\t%d\t%d\t%c\t%ld\t%s\n",
scrobbler_entry.artist,
scrobbler_entry.album?scrobbler_entry.album:"",
scrobbler_entry.title,
scrobbler_entry.tracknum,
(int)scrobbler_entry.length/1000,
"%s\t%s\t%s\t%s\t%d\t%c\t%ld\t%s\n",
id->artist,
id->album ?: "",
id->title,
tracknum,
(int)(id->length / 1000),
rating,
(long)timestamp,
scrobbler_entry.mb_track_id?scrobbler_entry.mb_track_id:"");
} else {
ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos),
SCROBBLER_CACHE_LEN,
"%s\t%s\t%s\t\t%d\t%c\t%ld\t%s\n",
scrobbler_entry.artist,
scrobbler_entry.album?scrobbler_entry.album:"",
scrobbler_entry.title,
(int)scrobbler_entry.length/1000,
rating,
(long)timestamp,
scrobbler_entry.mb_track_id?scrobbler_entry.mb_track_id:"");
}
get_timestamp(),
id->mb_track_id ?: "");
if ( ret >= SCROBBLER_CACHE_LEN )
{
logf("SCROBBLER: entry too long:");
logf("SCROBBLER: %s", scrobbler_entry.path);
} else {
logf("SCROBBLER: %s", id->path);
}
else
{
cache_pos++;
register_storage_idle_func(scrobbler_flush_callback);
}
@ -223,15 +202,11 @@ static void add_to_cache(unsigned long play_length)
static void scrobbler_change_event(void *data)
{
struct mp3entry *id = (struct mp3entry*)data;
/* add entry using the previous scrobbler_entry and timestamp */
if (pending)
add_to_cache(audio_prev_elapsed());
struct mp3entry *id = ((struct track_event *)data)->id3;
/* check if track was resumed > %50 played
check for blank artist or track name */
if ((id->elapsed > (id->length/2)) ||
(!id->artist ) || (!id->title ) )
if (id->elapsed > id->length / 2 || !id->artist || !id->title)
{
pending = false;
logf("SCROBBLER: skipping file %s", id->path);
@ -239,81 +214,85 @@ static void scrobbler_change_event(void *data)
else
{
logf("SCROBBLER: add pending");
copy_mp3entry(&scrobbler_entry, id);
#if CONFIG_RTC
timestamp = mktime(get_time());
#else
timestamp = 0;
#endif
record_timestamp();
pending = true;
}
}
static void scrobbler_finish_event(void *data)
{
struct track_event *te = (struct track_event *)data;
/* add entry using the currently ending track */
if (pending && (te->flags & TEF_CURRENT)
#if CONFIG_CODEC == SWCODEC
&& !(te->flags & TEF_REWIND)
#endif
)
{
pending = false;
add_to_cache(te->id3);
}
}
int scrobbler_init(void)
{
logf("SCROBBLER: init %d", global_settings.audioscrobbler);
if (scrobbler_initialised)
return 1;
if(!global_settings.audioscrobbler)
return -1;
scrobbler_cache = core_alloc("scrobbler",
SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
scrobbler_cache = core_alloc("scrobbler", SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
if (scrobbler_cache <= 0)
{
logf("SCROOBLER: OOM");
return -1;
}
add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, scrobbler_change_event);
cache_pos = 0;
pending = false;
scrobbler_initialised = true;
add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, scrobbler_change_event);
add_event(PLAYBACK_EVENT_TRACK_FINISH, false, scrobbler_finish_event);
return 1;
}
static void scrobbler_flush_cache(void)
{
if (scrobbler_initialised)
{
/* Add any pending entries to the cache */
if(pending)
add_to_cache(audio_prev_elapsed());
if (pending)
{
pending = false;
if (audio_status())
add_to_cache(audio_current_track());
}
/* Write the cache to disk if needed */
if (cache_pos)
write_cache();
pending = false;
}
}
void scrobbler_shutdown(void)
void scrobbler_shutdown(bool poweroff)
{
if (!scrobbler_initialised)
return;
remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
remove_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event);
scrobbler_flush_cache();
if (scrobbler_initialised)
if (!poweroff)
{
remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
scrobbler_initialised = false;
/* get rid of the buffer */
core_free(scrobbler_cache);
scrobbler_cache = 0;
}
}
void scrobbler_poweroff(void)
{
if (scrobbler_initialised && pending)
{
if ( audio_status() )
add_to_cache(audio_current_track()->elapsed);
else
add_to_cache(audio_prev_elapsed());
/* scrobbler_shutdown is called later, the cache will be written
* make sure the final track isn't added twice when that happens */
pending = false;
}
scrobbler_initialised = false;
}
bool scrobbler_is_enabled(void)

View file

@ -23,8 +23,7 @@
#define __SCROBBLER_H__
int scrobbler_init(void);
void scrobbler_shutdown(void);
void scrobbler_poweroff(void);
void scrobbler_shutdown(bool poweroff);
bool scrobbler_is_enabled(void);
#endif /* __SCROBBLER_H__ */

View file

@ -794,10 +794,13 @@ static int compare(const void *p1, const void *p2)
static void tagtree_buffer_event(void *data)
{
struct tagcache_search tcs;
struct mp3entry *id3 = (struct mp3entry*)data;
struct mp3entry *id3 = ((struct track_event *)data)->id3;
bool runtimedb = global_settings.runtimedb;
bool autoresume = global_settings.autoresume_enable;
/* Do not gather data unless proper setting has been enabled. */
if (!global_settings.runtimedb && !global_settings.autoresume_enable)
if (!runtimedb && !autoresume)
return;
logf("be:%s", id3->path);
@ -811,7 +814,7 @@ static void tagtree_buffer_event(void *data)
return;
}
if (global_settings.runtimedb)
if (runtimedb)
{
id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
if (!id3->rating)
@ -824,7 +827,7 @@ static void tagtree_buffer_event(void *data)
}
#if CONFIG_CODEC == SWCODEC
if (global_settings.autoresume_enable)
if (autoresume)
{
/* Load current file resume offset if not already defined (by
another resume mechanism) */
@ -846,18 +849,10 @@ static void tagtree_buffer_event(void *data)
static void tagtree_track_finish_event(void *data)
{
long lastplayed;
long tagcache_idx;
struct mp3entry *id3 = (struct mp3entry*)data;
struct track_event *te = (struct track_event *)data;
struct mp3entry *id3 = te->id3;
/* Do not gather data unless proper setting has been enabled. */
if (!global_settings.runtimedb && !global_settings.autoresume_enable)
{
logf("runtimedb gathering and autoresume not enabled");
return;
}
tagcache_idx=id3->tagcache_idx;
long tagcache_idx = id3->tagcache_idx;
if (!tagcache_idx)
{
logf("No tagcache index pointer found");
@ -865,26 +860,51 @@ static void tagtree_track_finish_event(void *data)
}
tagcache_idx--;
/* Don't process unplayed tracks, or tracks interrupted within the
first 15 seconds. */
if (id3->elapsed == 0
#if CONFIG_CODEC == SWCODEC /* HWCODEC doesn't have automatic_skip */
|| (id3->elapsed < 15 * 1000 && !audio_automatic_skip())
bool auto_skip = te->flags & TEF_AUTO_SKIP;
#endif
)
bool runtimedb = global_settings.runtimedb;
bool autoresume = global_settings.autoresume_enable;
/* Don't process unplayed tracks, or tracks interrupted within the
first 15 seconds but always process autoresume point */
if (runtimedb && (id3->elapsed == 0
#if CONFIG_CODEC == SWCODEC
|| (id3->elapsed < 15 * 1000 && !auto_skip)
#endif
))
{
logf("not logging unplayed or skipped track");
logf("not db logging unplayed or skipped track");
runtimedb = false;
}
#if CONFIG_CODEC == SWCODEC
/* 3s because that is the threshold the WPS uses to rewind instead
of skip backwards */
if (autoresume && (id3->elapsed == 0
|| (id3->elapsed < 3 * 1000 && !auto_skip)))
{
logf("not logging autoresume");
autoresume = false;
}
#endif
/* Do not gather data unless proper setting has been enabled and at least
one is still slated to be recorded */
if (!(runtimedb || autoresume))
{
logf("runtimedb gathering and autoresume not enabled/ignored");
return;
}
lastplayed = tagcache_increase_serial();
long lastplayed = tagcache_increase_serial();
if (lastplayed < 0)
{
logf("incorrect tc serial:%ld", lastplayed);
return;
}
if (global_settings.runtimedb)
if (runtimedb)
{
long playcount;
long playtime;
@ -906,10 +926,9 @@ static void tagtree_track_finish_event(void *data)
}
#if CONFIG_CODEC == SWCODEC
if (global_settings.autoresume_enable)
if (autoresume)
{
unsigned long offset
= audio_automatic_skip() ? 0 : id3->offset;
unsigned long offset = auto_skip ? 0 : id3->offset;
tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset);

View file

@ -236,12 +236,26 @@ int audio_get_spdif_sample_rate(void);
void audio_spdif_set_monitor(int monitor_spdif);
#endif /* HAVE_SPDIF_IN */
unsigned long audio_prev_elapsed(void);
#if CONFIG_CODEC != SWCODEC
/***********************************************************************/
/* audio event handling */
enum track_event_flags
{
TEF_NONE = 0x0, /* no flags are set */
TEF_CURRENT = 0x1, /* event is for the current track */
#if CONFIG_CODEC == SWCODEC
TEF_AUTO_SKIP = 0x2, /* event is sent in context of auto skip */
TEF_REWIND = 0x4, /* interpret as rewind, id3->elapsed is the
position before the seek back to 0 */
#endif /* CONFIG_CODEC == SWCODEC */
};
struct track_event
{
unsigned int flags; /* combo of enum track_event_flags values */
struct mp3entry *id3; /* pointer to mp3entry describing track */
};
#if CONFIG_CODEC != SWCODEC
/* subscribe to one or more audio event(s) by OR'ing together the desired */
/* event IDs (defined below); a handler is called with a solitary event ID */
/* (so switch() is okay) and possibly some useful data (depending on the */