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
diff --git a/apps/appevents.h b/apps/appevents.h
index 506f003..8677dbd 100644
--- a/apps/appevents.h
+++ b/apps/appevents.h
@@ -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,
};
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index a3d7a1b..726df6a 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -1190,7 +1190,7 @@
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)
{
diff --git a/apps/hosted/android/notification.c b/apps/hosted/android/notification.c
index 4bb8d0a..874cd3b 100644
--- a/apps/hosted/android/notification.c
+++ b/apps/hosted/android/notification.c
@@ -46,7 +46,7 @@
* 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 @@
* 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);
diff --git a/apps/main.c b/apps/main.c
index 7f44d89..7333f7d 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -420,7 +420,8 @@
global_settings.superbass);
#endif /* CONFIG_CODEC != SWCODEC */
- scrobbler_init();
+ if (global_settings.audioscrobbler)
+ scrobbler_init();
audio_init();
@@ -700,7 +701,10 @@
playlist_init();
tree_mem_init();
filetype_init();
- scrobbler_init();
+
+ if (global_settings.audioscrobbler)
+ scrobbler_init();
+
shortcuts_init();
#if CONFIG_CODEC != SWCODEC
diff --git a/apps/menus/playback_menu.c b/apps/menus/playback_menu.c
index dbfb44f..a82c88e 100644
--- a/apps/menus/playback_menu.c
+++ b/apps/menus/playback_menu.c
@@ -157,7 +157,7 @@
scrobbler_init();
if(scrobbler_is_enabled() && !global_settings.audioscrobbler)
- scrobbler_shutdown();
+ scrobbler_shutdown(false);
break;
}
return action;
diff --git a/apps/misc.c b/apps/misc.c
index 91244f2..8dff227 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -269,8 +269,6 @@
{
long msg_id = -1;
- scrobbler_poweroff();
-
#if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
if(!charger_inserted())
#endif
@@ -349,6 +347,7 @@
#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
audio_close_recording();
#endif
+ scrobbler_shutdown(true);
if(global_settings.talk_menu)
{
diff --git a/apps/mpeg.c b/apps/mpeg.c
index 5c206c7..2783a24 100644
--- a/apps/mpeg.c
+++ b/apps/mpeg.c
@@ -129,8 +129,6 @@
#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 @@
}
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 @@
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 @@
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 @@
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 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 @@
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 @@
{
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 @@
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 @@
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_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)
diff --git a/apps/playback.c b/apps/playback.c
index 8b498f2..a1db82e 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -155,13 +155,6 @@
/* 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 @@
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 @@
}
}
+/* 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 @@
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 @@
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_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 @@
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 @@
#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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
ff_rw_mode = false;
/* Manual skip */
- automatic_skip = false;
+ track_event_flags = TEF_NONE;
audio_playlist_track_finish();
@@ -2820,14 +2822,14 @@
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 @@
}
#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 @@
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)
{
diff --git a/apps/playback.h b/apps/playback.h
index 0a9d22c..f56bbfd 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -88,10 +88,6 @@
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 */
diff --git a/apps/root_menu.c b/apps/root_menu.c
index d03fee3..1ffde91 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -89,7 +89,7 @@
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)
diff --git a/apps/scrobbler.c b/apps/scrobbler.c
index be60cc1..efd0283 100644
--- a/apps/scrobbler.c
+++ b/apps/scrobbler.c
@@ -52,50 +52,40 @@
/* 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 @@
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 @@
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),
- 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,
- 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:"");
- }
+ 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%s\t%d\t%c\t%ld\t%s\n",
+ id->artist,
+ id->album ?: "",
+ id->title,
+ tracknum,
+ (int)(id->length / 1000),
+ rating,
+ 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 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 @@
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());
-
- /* Write the cache to disk if needed */
- if (cache_pos)
- write_cache();
-
+ 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();
}
-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)
diff --git a/apps/scrobbler.h b/apps/scrobbler.h
index d96b230..a3d1b36 100644
--- a/apps/scrobbler.h
+++ b/apps/scrobbler.h
@@ -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__ */
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 6b0c6aa..417b6f2 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -794,10 +794,13 @@
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 @@
return;
}
- if (global_settings.runtimedb)
+ if (runtimedb)
{
id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
if (!id3->rating)
@@ -824,7 +827,7 @@
}
#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_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 @@
}
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 @@
}
#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);
diff --git a/firmware/export/audio.h b/firmware/export/audio.h
index 24e8e9a..8108f50 100644
--- a/firmware/export/audio.h
+++ b/firmware/export/audio.h
@@ -236,12 +236,26 @@
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 */