summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/appevents.h24
-rw-r--r--apps/gui/wps.c2
-rw-r--r--apps/hosted/android/notification.c6
-rw-r--r--apps/main.c8
-rw-r--r--apps/menus/playback_menu.c2
-rw-r--r--apps/misc.c3
-rw-r--r--apps/mpeg.c54
-rw-r--r--apps/playback.c84
-rw-r--r--apps/playback.h4
-rw-r--r--apps/root_menu.c2
-rw-r--r--apps/scrobbler.c195
-rw-r--r--apps/scrobbler.h3
-rw-r--r--apps/tagtree.c71
-rw-r--r--firmware/export/audio.h20
14 files changed, 236 insertions, 242 deletions
diff --git a/apps/appevents.h b/apps/appevents.h
index 506f00329b..8677dbd522 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 a3d7a1bcf1..726df6add4 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -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)
{
diff --git a/apps/hosted/android/notification.c b/apps/hosted/android/notification.c
index 4bb8d0a528..874cd3bcef 100644
--- a/apps/hosted/android/notification.c
+++ b/apps/hosted/android/notification.c
@@ -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);
diff --git a/apps/main.c b/apps/main.c
index 7f44d89a6a..7333f7dc8d 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -420,7 +420,8 @@ static void init(void)
global_settings.superbass);
#endif /* CONFIG_CODEC != SWCODEC */
- scrobbler_init();
+ if (global_settings.audioscrobbler)
+ scrobbler_init();
audio_init();
@@ -700,7 +701,10 @@ static void init(void)
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 dbfb44f15d..a82c88e04a 100644
--- a/apps/menus/playback_menu.c
+++ b/apps/menus/playback_menu.c
@@ -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;
diff --git a/apps/misc.c b/apps/misc.c
index 91244f2c39..8dff227bc1 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -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)
{
diff --git a/apps/mpeg.c b/apps/mpeg.c
index 5c206c79f1..2783a24085 100644
--- a/apps/mpeg.c
+++ b/apps/mpeg.c
@@ -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)
diff --git a/apps/playback.c b/apps/playback.c
index 8b498f265e..a1db82eafd 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -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)
{
diff --git a/apps/playback.h b/apps/playback.h
index 0a9d22cde2..f56bbfdff0 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -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 */
diff --git a/apps/root_menu.c b/apps/root_menu.c
index d03fee35f7..1ffde91eb7 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -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)
diff --git a/apps/scrobbler.c b/apps/scrobbler.c
index be60cc15af..efd028327c 100644
--- a/apps/scrobbler.c
+++ b/apps/scrobbler.c
@@ -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),
- 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 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());
-
- /* 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 d96b230cb7..a3d1b361df 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 6b0c6aa3dd..417b6f28f0 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -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;
-
- /* 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;
- }
+ struct track_event *te = (struct track_event *)data;
+ struct mp3entry *id3 = te->id3;
- 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 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("not logging unplayed or skipped track");
+ 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);
diff --git a/firmware/export/audio.h b/firmware/export/audio.h
index 24e8e9a0e7..8108f50939 100644
--- a/firmware/export/audio.h
+++ b/firmware/export/audio.h
@@ -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 */