diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2013-07-12 12:06:38 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2013-07-13 00:08:51 -0400 |
commit | 023f6b6efd5407dc77c1253789f61baabb6607d6 (patch) | |
tree | 40d43117a7651715a2ce983eedff56b27962881a | |
parent | ffa8626b0c93f8a65e0e17190917f7f173160842 (diff) | |
download | rockbox-023f6b6efd5407dc77c1253789f61baabb6607d6.tar.gz rockbox-023f6b6efd5407dc77c1253789f61baabb6607d6.zip |
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
-rw-r--r-- | apps/appevents.h | 24 | ||||
-rw-r--r-- | apps/gui/wps.c | 2 | ||||
-rw-r--r-- | apps/hosted/android/notification.c | 6 | ||||
-rw-r--r-- | apps/main.c | 8 | ||||
-rw-r--r-- | apps/menus/playback_menu.c | 2 | ||||
-rw-r--r-- | apps/misc.c | 3 | ||||
-rw-r--r-- | apps/mpeg.c | 54 | ||||
-rw-r--r-- | apps/playback.c | 84 | ||||
-rw-r--r-- | apps/playback.h | 4 | ||||
-rw-r--r-- | apps/root_menu.c | 2 | ||||
-rw-r--r-- | apps/scrobbler.c | 195 | ||||
-rw-r--r-- | apps/scrobbler.h | 3 | ||||
-rw-r--r-- | apps/tagtree.c | 71 | ||||
-rw-r--r-- | firmware/export/audio.h | 20 |
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 @@ | |||
31 | 31 | ||
32 | /** Playback events **/ | 32 | /** Playback events **/ |
33 | enum { | 33 | enum { |
34 | /* Playback is starting from a stopped state */ | 34 | /* Playback is starting from a stopped state |
35 | data = NULL */ | ||
35 | PLAYBACK_EVENT_START_PLAYBACK = (EVENT_CLASS_PLAYBACK|1), | 36 | PLAYBACK_EVENT_START_PLAYBACK = (EVENT_CLASS_PLAYBACK|1), |
36 | /* Audio has begun buffering for decoding track (or is already completed) */ | 37 | /* Audio has begun buffering for decoding track (or is already completed) |
38 | data = &(struct track_event){} */ | ||
37 | PLAYBACK_EVENT_TRACK_BUFFER, | 39 | PLAYBACK_EVENT_TRACK_BUFFER, |
38 | /* Handles for current user track are ready (other than audio or codec) */ | 40 | /* Handles for current user track are ready (other than audio or codec) |
41 | data = &(struct track_event){} */ | ||
39 | PLAYBACK_EVENT_CUR_TRACK_READY, | 42 | PLAYBACK_EVENT_CUR_TRACK_READY, |
40 | /* Current user track finished */ | 43 | /* Current user track finished |
44 | data = &(struct track_event){} */ | ||
41 | PLAYBACK_EVENT_TRACK_FINISH, | 45 | PLAYBACK_EVENT_TRACK_FINISH, |
42 | /* A new current user track has begun */ | 46 | /* A new current user track has begun |
47 | data = &(struct track_event){} */ | ||
43 | PLAYBACK_EVENT_TRACK_CHANGE, | 48 | PLAYBACK_EVENT_TRACK_CHANGE, |
44 | /* A manual skip is about to be processed */ | 49 | /* A manual skip is about to be processed |
50 | data = NULL */ | ||
45 | PLAYBACK_EVENT_TRACK_SKIP, | 51 | PLAYBACK_EVENT_TRACK_SKIP, |
46 | /* Next track medadata was just loaded */ | 52 | /* Next track medadata was just loaded |
53 | data = &(struct track_event){} */ | ||
47 | PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, | 54 | PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, |
48 | /* Voice is playing: data = &(bool){true|false} */ | 55 | /* Voice is playing |
56 | data = &(bool){true|false} */ | ||
49 | PLAYBACK_EVENT_VOICE_PLAYING, | 57 | PLAYBACK_EVENT_VOICE_PLAYING, |
50 | }; | 58 | }; |
51 | 59 | ||
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) | |||
1190 | static void track_changed_callback(void *param) | 1190 | static void track_changed_callback(void *param) |
1191 | { | 1191 | { |
1192 | struct wps_state *state = skin_get_global_state(); | 1192 | struct wps_state *state = skin_get_global_state(); |
1193 | state->id3 = (struct mp3entry*)param; | 1193 | state->id3 = ((struct track_event *)param)->id3; |
1194 | state->nid3 = audio_next_track(); | 1194 | state->nid3 = audio_next_track(); |
1195 | if (state->id3->cuesheet) | 1195 | if (state->id3->cuesheet) |
1196 | { | 1196 | { |
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 }; | |||
46 | * notify about track change, and show track info */ | 46 | * notify about track change, and show track info */ |
47 | static void track_changed_callback(void *param) | 47 | static void track_changed_callback(void *param) |
48 | { | 48 | { |
49 | struct mp3entry* id3 = (struct mp3entry*)param; | 49 | struct mp3entry* id3 = ((struct track_event *)param)->id3; |
50 | JNIEnv e = *env_ptr; | 50 | JNIEnv e = *env_ptr; |
51 | if (id3) | 51 | if (id3) |
52 | { | 52 | { |
@@ -108,7 +108,9 @@ static void track_changed_callback(void *param) | |||
108 | * notify about track finishing */ | 108 | * notify about track finishing */ |
109 | static void track_finished_callback(void *param) | 109 | static void track_finished_callback(void *param) |
110 | { | 110 | { |
111 | (void)param; | 111 | if (((struct track_event *)param)->flags & TEF_REWIND) |
112 | return; /* Not a true track end */ | ||
113 | |||
112 | JNIEnv e = *env_ptr; | 114 | JNIEnv e = *env_ptr; |
113 | e->CallVoidMethod(env_ptr, NotificationManager_instance, | 115 | e->CallVoidMethod(env_ptr, NotificationManager_instance, |
114 | finishNotification); | 116 | 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) | |||
420 | global_settings.superbass); | 420 | global_settings.superbass); |
421 | #endif /* CONFIG_CODEC != SWCODEC */ | 421 | #endif /* CONFIG_CODEC != SWCODEC */ |
422 | 422 | ||
423 | scrobbler_init(); | 423 | if (global_settings.audioscrobbler) |
424 | scrobbler_init(); | ||
424 | 425 | ||
425 | audio_init(); | 426 | audio_init(); |
426 | 427 | ||
@@ -700,7 +701,10 @@ static void init(void) | |||
700 | playlist_init(); | 701 | playlist_init(); |
701 | tree_mem_init(); | 702 | tree_mem_init(); |
702 | filetype_init(); | 703 | filetype_init(); |
703 | scrobbler_init(); | 704 | |
705 | if (global_settings.audioscrobbler) | ||
706 | scrobbler_init(); | ||
707 | |||
704 | shortcuts_init(); | 708 | shortcuts_init(); |
705 | 709 | ||
706 | #if CONFIG_CODEC != SWCODEC | 710 | #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 | |||
157 | scrobbler_init(); | 157 | scrobbler_init(); |
158 | 158 | ||
159 | if(scrobbler_is_enabled() && !global_settings.audioscrobbler) | 159 | if(scrobbler_is_enabled() && !global_settings.audioscrobbler) |
160 | scrobbler_shutdown(); | 160 | scrobbler_shutdown(false); |
161 | break; | 161 | break; |
162 | } | 162 | } |
163 | return action; | 163 | 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) | |||
269 | { | 269 | { |
270 | long msg_id = -1; | 270 | long msg_id = -1; |
271 | 271 | ||
272 | scrobbler_poweroff(); | ||
273 | |||
274 | #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) | 272 | #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) |
275 | if(!charger_inserted()) | 273 | if(!charger_inserted()) |
276 | #endif | 274 | #endif |
@@ -349,6 +347,7 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) | |||
349 | #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC | 347 | #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC |
350 | audio_close_recording(); | 348 | audio_close_recording(); |
351 | #endif | 349 | #endif |
350 | scrobbler_shutdown(true); | ||
352 | 351 | ||
353 | if(global_settings.talk_menu) | 352 | if(global_settings.talk_menu) |
354 | { | 353 | { |
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; | |||
129 | 129 | ||
130 | #ifndef SIMULATOR | 130 | #ifndef SIMULATOR |
131 | static void stop_playing(void); | 131 | static void stop_playing(void); |
132 | /* Play time of the previous track */ | ||
133 | static unsigned long prev_track_elapsed; | ||
134 | 132 | ||
135 | static int track_read_idx = 0; | 133 | static int track_read_idx = 0; |
136 | static int track_write_idx = 0; | 134 | static int track_write_idx = 0; |
@@ -362,7 +360,15 @@ static bool audio_dispatch_event(unsigned short event, unsigned long data) | |||
362 | } | 360 | } |
363 | return false; | 361 | return false; |
364 | } | 362 | } |
365 | #endif | 363 | |
364 | static void send_track_event(unsigned int id, struct mp3entry *id3) | ||
365 | { | ||
366 | struct mp3entry *cur_id3 = | ||
367 | &trackdata[track_read_idx & MAX_TRACK_ENTRIES_MASK].id3; | ||
368 | unsigned int flags = id3 == cur_id3 ? TEF_CURRENT : 0; | ||
369 | send_event(id, &(struct track_event){ .flags = flags, .id3 = id3 }); | ||
370 | } | ||
371 | #endif /* SIMULATOR */ | ||
366 | 372 | ||
367 | /***********************************************************************/ | 373 | /***********************************************************************/ |
368 | 374 | ||
@@ -609,7 +615,7 @@ static void generate_unbuffer_events(void) | |||
609 | for (i = 0; i < numentries; i++) | 615 | for (i = 0; i < numentries; i++) |
610 | { | 616 | { |
611 | /* Send an event to notify that track has finished. */ | 617 | /* Send an event to notify that track has finished. */ |
612 | send_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3); | 618 | send_track_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3); |
613 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | 619 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; |
614 | } | 620 | } |
615 | } | 621 | } |
@@ -623,7 +629,7 @@ static void generate_postbuffer_events(void) | |||
623 | 629 | ||
624 | for (i = 0; i < numentries; i++) | 630 | for (i = 0; i < numentries; i++) |
625 | { | 631 | { |
626 | send_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3); | 632 | send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3); |
627 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | 633 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; |
628 | } | 634 | } |
629 | } | 635 | } |
@@ -1006,7 +1012,7 @@ static struct trackdata *add_track_to_tag_list(const char *filename) | |||
1006 | send_nid3_event = (track_write_idx == track_read_idx + 1); | 1012 | send_nid3_event = (track_write_idx == track_read_idx + 1); |
1007 | track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; | 1013 | track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; |
1008 | if (send_nid3_event) | 1014 | if (send_nid3_event) |
1009 | send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL); | 1015 | send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, &track->id3); |
1010 | debug_tags(); | 1016 | debug_tags(); |
1011 | return track; | 1017 | return track; |
1012 | } | 1018 | } |
@@ -1093,17 +1099,11 @@ static int new_file(int steps) | |||
1093 | 1099 | ||
1094 | static void stop_playing(void) | 1100 | static void stop_playing(void) |
1095 | { | 1101 | { |
1096 | struct trackdata *track; | ||
1097 | |||
1098 | /* Stop the current stream */ | 1102 | /* Stop the current stream */ |
1099 | mp3_play_stop(); | 1103 | mp3_play_stop(); |
1100 | playing = false; | 1104 | playing = false; |
1101 | filling = false; | 1105 | filling = false; |
1102 | 1106 | ||
1103 | track = get_trackdata(0); | ||
1104 | if (track != NULL) | ||
1105 | prev_track_elapsed = track->id3.elapsed; | ||
1106 | |||
1107 | if(mpeg_file >= 0) | 1107 | if(mpeg_file >= 0) |
1108 | close(mpeg_file); | 1108 | close(mpeg_file); |
1109 | mpeg_file = -1; | 1109 | mpeg_file = -1; |
@@ -1112,17 +1112,12 @@ static void stop_playing(void) | |||
1112 | reset_mp3_buffer(); | 1112 | reset_mp3_buffer(); |
1113 | } | 1113 | } |
1114 | 1114 | ||
1115 | static void end_current_track(void) { | 1115 | static void end_current_track(void) |
1116 | struct trackdata *track; | 1116 | { |
1117 | |||
1118 | play_pending = false; | 1117 | play_pending = false; |
1119 | playing = false; | 1118 | playing = false; |
1120 | mp3_play_pause(false); | 1119 | mp3_play_pause(false); |
1121 | 1120 | ||
1122 | track = get_trackdata(0); | ||
1123 | if (track != NULL) | ||
1124 | prev_track_elapsed = track->id3.elapsed; | ||
1125 | |||
1126 | reset_mp3_buffer(); | 1121 | reset_mp3_buffer(); |
1127 | remove_all_tags(); | 1122 | remove_all_tags(); |
1128 | generate_unbuffer_events(); | 1123 | generate_unbuffer_events(); |
@@ -1164,9 +1159,6 @@ static void track_change(void) | |||
1164 | { | 1159 | { |
1165 | DEBUGF("Track change\n"); | 1160 | DEBUGF("Track change\n"); |
1166 | 1161 | ||
1167 | struct trackdata *track = get_trackdata(0); | ||
1168 | prev_track_elapsed = track->id3.elapsed; | ||
1169 | |||
1170 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 1162 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
1171 | /* Reset the AVC */ | 1163 | /* Reset the AVC */ |
1172 | sound_set_avc(-1); | 1164 | sound_set_avc(-1); |
@@ -1177,17 +1169,15 @@ static void track_change(void) | |||
1177 | remove_current_tag(); | 1169 | remove_current_tag(); |
1178 | update_playlist(); | 1170 | update_playlist(); |
1179 | if (is_playing) | 1171 | if (is_playing) |
1180 | send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track()); | 1172 | { |
1173 | send_track_event(PLAYBACK_EVENT_TRACK_CHANGE, | ||
1174 | audio_current_track()); | ||
1175 | } | ||
1181 | } | 1176 | } |
1182 | 1177 | ||
1183 | current_track_counter++; | 1178 | current_track_counter++; |
1184 | } | 1179 | } |
1185 | 1180 | ||
1186 | unsigned long audio_prev_elapsed(void) | ||
1187 | { | ||
1188 | return prev_track_elapsed; | ||
1189 | } | ||
1190 | |||
1191 | #ifdef DEBUG | 1181 | #ifdef DEBUG |
1192 | void hexdump(const unsigned char *buf, int len) | 1182 | void hexdump(const unsigned char *buf, int len) |
1193 | { | 1183 | { |
@@ -1229,7 +1219,8 @@ static void start_playback_if_ready(void) | |||
1229 | if (play_pending_track_change) | 1219 | if (play_pending_track_change) |
1230 | { | 1220 | { |
1231 | play_pending_track_change = false; | 1221 | play_pending_track_change = false; |
1232 | send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track()); | 1222 | send_track_event(PLAYBACK_EVENT_TRACK_CHANGE, |
1223 | audio_current_track()); | ||
1233 | } | 1224 | } |
1234 | play_pending = false; | 1225 | play_pending = false; |
1235 | } | 1226 | } |
@@ -2828,11 +2819,6 @@ void audio_play(long offset) | |||
2828 | void audio_stop(void) | 2819 | void audio_stop(void) |
2829 | { | 2820 | { |
2830 | #ifndef SIMULATOR | 2821 | #ifndef SIMULATOR |
2831 | if (playing) | ||
2832 | { | ||
2833 | struct trackdata *track = get_trackdata(0); | ||
2834 | prev_track_elapsed = track->id3.elapsed; | ||
2835 | } | ||
2836 | mpeg_stop_done = false; | 2822 | mpeg_stop_done = false; |
2837 | queue_post(&mpeg_queue, MPEG_STOP, 0); | 2823 | queue_post(&mpeg_queue, MPEG_STOP, 0); |
2838 | while(!mpeg_stop_done) | 2824 | 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) */ | |||
155 | /* Peeking functions can yield and mess us up */ | 155 | /* Peeking functions can yield and mess us up */ |
156 | static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/ | 156 | static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/ |
157 | 157 | ||
158 | |||
159 | /** For Scrobbler support **/ | ||
160 | |||
161 | /* Previous track elapsed time */ | ||
162 | static unsigned long prev_track_elapsed = 0; /* (A,O-) */ | ||
163 | |||
164 | |||
165 | /** For album art support **/ | 158 | /** For album art support **/ |
166 | #define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT | 159 | #define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT |
167 | #ifdef HAVE_ALBUMART | 160 | #ifdef HAVE_ALBUMART |
@@ -296,9 +289,8 @@ enum track_skip_type | |||
296 | would work as expected */ | 289 | would work as expected */ |
297 | 290 | ||
298 | /* Used to indicate status for the events. Must be separate to satisfy all | 291 | /* Used to indicate status for the events. Must be separate to satisfy all |
299 | clients so the correct metadata is read when sending the change events | 292 | clients so the correct metadata is read when sending the change events. */ |
300 | and also so that it is read correctly outside the events. */ | 293 | static unsigned int track_event_flags = TEF_NONE; /* (A, O-) */ |
301 | static bool automatic_skip = false; /* (A, O-) */ | ||
302 | 294 | ||
303 | /* Pending manual track skip offset */ | 295 | /* Pending manual track skip offset */ |
304 | static int skip_offset = 0; /* (A, O) */ | 296 | static int skip_offset = 0; /* (A, O) */ |
@@ -1056,6 +1048,16 @@ static void audio_handle_track_load_status(int trackstat) | |||
1056 | } | 1048 | } |
1057 | } | 1049 | } |
1058 | 1050 | ||
1051 | /* Send track events that use a struct track_event for data */ | ||
1052 | static void send_track_event(unsigned int id, unsigned int flags, | ||
1053 | struct mp3entry *id3) | ||
1054 | { | ||
1055 | if (id3 == id3_get(PLAYING_ID3)) | ||
1056 | flags |= TEF_CURRENT; | ||
1057 | |||
1058 | send_event(id, &(struct track_event){ .flags = flags, .id3 = id3 }); | ||
1059 | } | ||
1060 | |||
1059 | /* Announce the end of playing the current track */ | 1061 | /* Announce the end of playing the current track */ |
1060 | static void audio_playlist_track_finish(void) | 1062 | static void audio_playlist_track_finish(void) |
1061 | { | 1063 | { |
@@ -1066,12 +1068,8 @@ static void audio_playlist_track_finish(void) | |||
1066 | 1068 | ||
1067 | if (id3) | 1069 | if (id3) |
1068 | { | 1070 | { |
1069 | send_event(PLAYBACK_EVENT_TRACK_FINISH, id3); | 1071 | send_track_event(PLAYBACK_EVENT_TRACK_FINISH, |
1070 | prev_track_elapsed = id3->elapsed; | 1072 | track_event_flags, id3); |
1071 | } | ||
1072 | else | ||
1073 | { | ||
1074 | prev_track_elapsed = 0; | ||
1075 | } | 1073 | } |
1076 | } | 1074 | } |
1077 | 1075 | ||
@@ -1081,7 +1079,10 @@ static void audio_playlist_track_change(void) | |||
1081 | struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3)); | 1079 | struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3)); |
1082 | 1080 | ||
1083 | if (id3) | 1081 | if (id3) |
1084 | send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3); | 1082 | { |
1083 | send_track_event(PLAYBACK_EVENT_TRACK_CHANGE, | ||
1084 | track_event_flags, id3); | ||
1085 | } | ||
1085 | 1086 | ||
1086 | position_key = pcmbuf_get_position_key(); | 1087 | position_key = pcmbuf_get_position_key(); |
1087 | 1088 | ||
@@ -1092,8 +1093,8 @@ static void audio_playlist_track_change(void) | |||
1092 | static void audio_update_and_announce_next_track(const struct mp3entry *id3_next) | 1093 | static void audio_update_and_announce_next_track(const struct mp3entry *id3_next) |
1093 | { | 1094 | { |
1094 | id3_write_locked(NEXTTRACK_ID3, id3_next); | 1095 | id3_write_locked(NEXTTRACK_ID3, id3_next); |
1095 | send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, | 1096 | send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, |
1096 | id3_get(NEXTTRACK_ID3)); | 1097 | 0, id3_get(NEXTTRACK_ID3)); |
1097 | } | 1098 | } |
1098 | 1099 | ||
1099 | /* Bring the user current mp3entry up to date and set a new offset for the | 1100 | /* 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) | |||
1441 | bool resume = !auto_skip; | 1442 | bool resume = !auto_skip; |
1442 | 1443 | ||
1443 | /* Send the "buffer" event to obtain the resume position for the codec */ | 1444 | /* Send the "buffer" event to obtain the resume position for the codec */ |
1444 | send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3); | 1445 | send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, 0, cur_id3); |
1445 | 1446 | ||
1446 | if (!resume) | 1447 | if (!resume) |
1447 | { | 1448 | { |
@@ -1497,7 +1498,7 @@ static bool audio_start_codec(bool auto_skip) | |||
1497 | #endif | 1498 | #endif |
1498 | { | 1499 | { |
1499 | /* Send the "buffer" event now */ | 1500 | /* Send the "buffer" event now */ |
1500 | send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3); | 1501 | send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, 0, cur_id3); |
1501 | } | 1502 | } |
1502 | 1503 | ||
1503 | buf_pin_handle(info->id3_hid, false); | 1504 | buf_pin_handle(info->id3_hid, false); |
@@ -1893,7 +1894,8 @@ static int audio_finish_load_track(struct track_info *info) | |||
1893 | /* Send only when the track handles could not all be opened ahead of | 1894 | /* Send only when the track handles could not all be opened ahead of |
1894 | time for the user's current track - otherwise everything is ready | 1895 | time for the user's current track - otherwise everything is ready |
1895 | by the time PLAYBACK_EVENT_TRACK_CHANGE is sent */ | 1896 | by the time PLAYBACK_EVENT_TRACK_CHANGE is sent */ |
1896 | send_event(PLAYBACK_EVENT_CUR_TRACK_READY, id3_get(PLAYING_ID3)); | 1897 | send_track_event(PLAYBACK_EVENT_CUR_TRACK_READY, 0, |
1898 | id3_get(PLAYING_ID3)); | ||
1897 | } | 1899 | } |
1898 | 1900 | ||
1899 | #ifdef HAVE_CODEC_BUFFERING | 1901 | #ifdef HAVE_CODEC_BUFFERING |
@@ -2157,7 +2159,7 @@ static void audio_on_finish_load_track(int id3_hid) | |||
2157 | buf_read_cuesheet(info->cuesheet_hid); | 2159 | buf_read_cuesheet(info->cuesheet_hid); |
2158 | } | 2160 | } |
2159 | 2161 | ||
2160 | if (audio_start_codec(automatic_skip)) | 2162 | if (audio_start_codec(track_event_flags & TEF_AUTO_SKIP)) |
2161 | { | 2163 | { |
2162 | if (is_user_current) | 2164 | if (is_user_current) |
2163 | { | 2165 | { |
@@ -2356,7 +2358,7 @@ static void audio_on_codec_complete(int status) | |||
2356 | 2358 | ||
2357 | int trackstat = LOAD_TRACK_OK; | 2359 | int trackstat = LOAD_TRACK_OK; |
2358 | 2360 | ||
2359 | automatic_skip = true; | 2361 | track_event_flags = TEF_AUTO_SKIP; |
2360 | skip_pending = TRACK_SKIP_AUTO; | 2362 | skip_pending = TRACK_SKIP_AUTO; |
2361 | 2363 | ||
2362 | /* Does this track have an entry allocated? */ | 2364 | /* Does this track have an entry allocated? */ |
@@ -2471,7 +2473,7 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2471 | 2473 | ||
2472 | halt_decoding_track(true); | 2474 | halt_decoding_track(true); |
2473 | 2475 | ||
2474 | automatic_skip = false; | 2476 | track_event_flags = TEF_NONE; |
2475 | ff_rw_mode = false; | 2477 | ff_rw_mode = false; |
2476 | 2478 | ||
2477 | if (flags & AUDIO_START_RESTART) | 2479 | if (flags & AUDIO_START_RESTART) |
@@ -2595,7 +2597,7 @@ static void audio_stop_playback(void) | |||
2595 | audio_playlist_track_finish(); | 2597 | audio_playlist_track_finish(); |
2596 | 2598 | ||
2597 | skip_pending = TRACK_SKIP_NONE; | 2599 | skip_pending = TRACK_SKIP_NONE; |
2598 | automatic_skip = false; | 2600 | track_event_flags = TEF_NONE; |
2599 | 2601 | ||
2600 | /* Close all tracks and mark them NULL */ | 2602 | /* Close all tracks and mark them NULL */ |
2601 | remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback); | 2603 | remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback); |
@@ -2667,7 +2669,7 @@ static void audio_on_skip(void) | |||
2667 | ff_rw_mode = false; | 2669 | ff_rw_mode = false; |
2668 | 2670 | ||
2669 | /* Manual skip */ | 2671 | /* Manual skip */ |
2670 | automatic_skip = false; | 2672 | track_event_flags = TEF_NONE; |
2671 | 2673 | ||
2672 | /* If there was an auto skip in progress, there will be residual | 2674 | /* If there was an auto skip in progress, there will be residual |
2673 | advancement of the playlist and/or track list so compensation will be | 2675 | advancement of the playlist and/or track list so compensation will be |
@@ -2755,7 +2757,7 @@ static void audio_on_dir_skip(int direction) | |||
2755 | ff_rw_mode = false; | 2757 | ff_rw_mode = false; |
2756 | 2758 | ||
2757 | /* Manual skip */ | 2759 | /* Manual skip */ |
2758 | automatic_skip = false; | 2760 | track_event_flags = TEF_NONE; |
2759 | 2761 | ||
2760 | audio_playlist_track_finish(); | 2762 | audio_playlist_track_finish(); |
2761 | 2763 | ||
@@ -2820,14 +2822,14 @@ static void audio_on_ff_rewind(long time) | |||
2820 | struct mp3entry *id3 = id3_get(PLAYING_ID3); | 2822 | struct mp3entry *id3 = id3_get(PLAYING_ID3); |
2821 | struct mp3entry *ci_id3 = id3_get(CODEC_ID3); | 2823 | struct mp3entry *ci_id3 = id3_get(CODEC_ID3); |
2822 | 2824 | ||
2823 | automatic_skip = false; | 2825 | track_event_flags = TEF_NONE; |
2824 | 2826 | ||
2825 | /* Send event before clobbering the time */ | 2827 | /* Send event before clobbering the time if rewinding. */ |
2826 | /* FIXME: Nasty, but the tagtree expects this so that rewinding and | ||
2827 | then skipping back to this track resumes properly. Something else | ||
2828 | should be sent. We're not _really_ finishing the track are we? */ | ||
2829 | if (time == 0) | 2828 | if (time == 0) |
2830 | send_event(PLAYBACK_EVENT_TRACK_FINISH, id3); | 2829 | { |
2830 | send_track_event(PLAYBACK_EVENT_TRACK_FINISH, | ||
2831 | track_event_flags | TEF_REWIND, id3); | ||
2832 | } | ||
2831 | 2833 | ||
2832 | id3->elapsed = time; | 2834 | id3->elapsed = time; |
2833 | queue_reply(&audio_queue, 1); | 2835 | queue_reply(&audio_queue, 1); |
@@ -3662,14 +3664,6 @@ void playback_release_aa_slot(int slot) | |||
3662 | } | 3664 | } |
3663 | #endif /* HAVE_ALBUMART */ | 3665 | #endif /* HAVE_ALBUMART */ |
3664 | 3666 | ||
3665 | /* Is an automatic skip in progress? If called outside transition callbacks, | ||
3666 | indicates the last skip type at the time it was processed and isn't very | ||
3667 | meaningful. */ | ||
3668 | bool audio_automatic_skip(void) | ||
3669 | { | ||
3670 | return automatic_skip; | ||
3671 | } | ||
3672 | |||
3673 | /* Would normally calculate byte offset from an elapsed time but is not | 3667 | /* Would normally calculate byte offset from an elapsed time but is not |
3674 | used on SWCODEC */ | 3668 | used on SWCODEC */ |
3675 | int audio_get_file_pos(void) | 3669 | int audio_get_file_pos(void) |
@@ -3677,12 +3671,6 @@ int audio_get_file_pos(void) | |||
3677 | return 0; | 3671 | return 0; |
3678 | } | 3672 | } |
3679 | 3673 | ||
3680 | /* Return the elapsed time of the track previous to the current */ | ||
3681 | unsigned long audio_prev_elapsed(void) | ||
3682 | { | ||
3683 | return prev_track_elapsed; | ||
3684 | } | ||
3685 | |||
3686 | /* Return total file buffer length after accounting for the talk buf */ | 3674 | /* Return total file buffer length after accounting for the talk buf */ |
3687 | size_t audio_get_filebuflen(void) | 3675 | size_t audio_get_filebuflen(void) |
3688 | { | 3676 | { |
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 | |||
88 | bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */ | 88 | bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */ |
89 | size_t audio_get_filebuflen(void); | 89 | size_t audio_get_filebuflen(void); |
90 | 90 | ||
91 | /* Automatic transition? Only valid to call during the track change events, | ||
92 | otherwise the result is undefined. */ | ||
93 | bool audio_automatic_skip(void); | ||
94 | |||
95 | unsigned int playback_status(void); | 91 | unsigned int playback_status(void); |
96 | 92 | ||
97 | #endif /* _PLAYBACK_H */ | 93 | #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 | |||
89 | static char current_track_path[MAX_PATH]; | 89 | static char current_track_path[MAX_PATH]; |
90 | static void rootmenu_track_changed_callback(void* param) | 90 | static void rootmenu_track_changed_callback(void* param) |
91 | { | 91 | { |
92 | struct mp3entry *id3 = (struct mp3entry *)param; | 92 | struct mp3entry *id3 = ((struct track_event *)param)->id3; |
93 | strlcpy(current_track_path, id3->path, MAX_PATH); | 93 | strlcpy(current_track_path, id3->path, MAX_PATH); |
94 | } | 94 | } |
95 | static int browser(void* param) | 95 | 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 | |||
52 | /* longest entry I've had is 323, add a safety margin */ | 52 | /* longest entry I've had is 323, add a safety margin */ |
53 | #define SCROBBLER_CACHE_LEN 512 | 53 | #define SCROBBLER_CACHE_LEN 512 |
54 | 54 | ||
55 | static int scrobbler_cache; | ||
56 | |||
57 | static int cache_pos; | ||
58 | static struct mp3entry scrobbler_entry; | ||
59 | static bool pending = false; | ||
60 | static bool scrobbler_initialised = false; | 55 | static bool scrobbler_initialised = false; |
56 | static int scrobbler_cache = 0; | ||
57 | static int cache_pos = 0; | ||
58 | static bool pending = false; | ||
61 | #if CONFIG_RTC | 59 | #if CONFIG_RTC |
62 | static time_t timestamp; | 60 | static time_t timestamp; |
63 | #else | 61 | #define BASE_FILENAME ".scrobbler.log" |
64 | static unsigned long timestamp; | 62 | #define HDR_STR_TIMELESS |
65 | #endif | 63 | #define get_timestamp() ((long)timestamp) |
66 | 64 | #define record_timestamp() ((void)(timestamp = mktime(get_time()))) | |
67 | /* Crude work-around for Archos Sims - return a set amount */ | 65 | #else /* !CONFIG_RTC */ |
68 | #if (CONFIG_CODEC != SWCODEC) && (CONFIG_PLATFORM & PLATFORM_HOSTED) | 66 | #define HDR_STR_TIMELESS " Timeless" |
69 | unsigned long audio_prev_elapsed(void) | 67 | #define BASE_FILENAME ".scrobbler-timeless.log" |
70 | { | 68 | #define get_timestamp() (0l) |
71 | return 120000; | 69 | #define record_timestamp() ({}) |
72 | } | 70 | #endif /* CONFIG_RTC */ |
73 | #endif | ||
74 | 71 | ||
75 | static void get_scrobbler_filename(char *path, size_t size) | 72 | static void get_scrobbler_filename(char *path, size_t size) |
76 | { | 73 | { |
77 | int used; | 74 | int used; |
78 | |||
79 | #if CONFIG_RTC | ||
80 | const char *base_filename = ".scrobbler.log"; | ||
81 | #else | ||
82 | const char *base_filename = ".scrobbler-timeless.log"; | ||
83 | #endif | ||
84 | |||
85 | /* Get location of USB mass storage area */ | 75 | /* Get location of USB mass storage area */ |
86 | #ifdef APPLICATION | 76 | #ifdef APPLICATION |
87 | #if (CONFIG_PLATFORM & PLATFORM_MAEMO) | 77 | #if (CONFIG_PLATFORM & PLATFORM_MAEMO) |
88 | used = snprintf(path, size, "/home/user/MyDocs/%s", base_filename); | 78 | used = snprintf(path, size, "/home/user/MyDocs/%s", BASE_FILENAME); |
89 | #elif (CONFIG_PLATFORM & PLATFORM_ANDROID) | 79 | #elif (CONFIG_PLATFORM & PLATFORM_ANDROID) |
90 | used = snprintf(path, size, "/sdcard/%s", base_filename); | 80 | used = snprintf(path, size, "/sdcard/%s", BASE_FILENAME); |
91 | #elif defined (SAMSUNG_YPR0) | 81 | #elif defined (SAMSUNG_YPR0) |
92 | used = snprintf(path, size, "%s/%s", HOME_DIR, base_filename); | 82 | used = snprintf(path, size, "%s/%s", HOME_DIR, BASE_FILENAME); |
93 | #else /* SDL/unknown RaaA build */ | 83 | #else /* SDL/unknown RaaA build */ |
94 | used = snprintf(path, size, "%s/%s", ROCKBOX_DIR, base_filename); | 84 | used = snprintf(path, size, "%s/%s", ROCKBOX_DIR, BASE_FILENAME); |
95 | #endif /* (CONFIG_PLATFORM & PLATFORM_MAEMO) */ | 85 | #endif /* (CONFIG_PLATFORM & PLATFORM_MAEMO) */ |
96 | 86 | ||
97 | #else | 87 | #else |
98 | used = snprintf(path, size, "/%s", base_filename); | 88 | used = snprintf(path, size, "/%s", BASE_FILENAME); |
99 | #endif | 89 | #endif |
100 | 90 | ||
101 | if (used >= (int)size) | 91 | if (used >= (int)size) |
@@ -121,12 +111,9 @@ static void write_cache(void) | |||
121 | if(fd >= 0) | 111 | if(fd >= 0) |
122 | { | 112 | { |
123 | fdprintf(fd, "#AUDIOSCROBBLER/" SCROBBLER_VERSION "\n" | 113 | fdprintf(fd, "#AUDIOSCROBBLER/" SCROBBLER_VERSION "\n" |
124 | "#TZ/UNKNOWN\n" | 114 | "#TZ/UNKNOWN\n" "#CLIENT/Rockbox " |
125 | #if CONFIG_RTC | 115 | TARGET_NAME SCROBBLER_REVISION |
126 | "#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION "\n"); | 116 | HDR_STR_TIMELESS "\n"); |
127 | #else | ||
128 | "#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION " Timeless\n"); | ||
129 | #endif | ||
130 | 117 | ||
131 | close(fd); | 118 | close(fd); |
132 | } | 119 | } |
@@ -170,51 +157,43 @@ static void scrobbler_flush_callback(void *data) | |||
170 | write_cache(); | 157 | write_cache(); |
171 | } | 158 | } |
172 | 159 | ||
173 | static void add_to_cache(unsigned long play_length) | 160 | static void add_to_cache(const struct mp3entry *id) |
174 | { | 161 | { |
175 | if ( cache_pos >= SCROBBLER_MAX_CACHE ) | 162 | if ( cache_pos >= SCROBBLER_MAX_CACHE ) |
176 | write_cache(); | 163 | write_cache(); |
177 | 164 | ||
178 | int ret; | ||
179 | char rating = 'S'; /* Skipped */ | 165 | char rating = 'S'; /* Skipped */ |
180 | char* scrobbler_buf = core_get_data(scrobbler_cache); | 166 | char* scrobbler_buf = core_get_data(scrobbler_cache); |
181 | 167 | ||
182 | logf("SCROBBLER: add_to_cache[%d]", cache_pos); | 168 | logf("SCROBBLER: add_to_cache[%d]", cache_pos); |
183 | 169 | ||
184 | if ( play_length > (scrobbler_entry.length/2) ) | 170 | if (id->elapsed > id->length / 2) |
185 | rating = 'L'; /* Listened */ | 171 | rating = 'L'; /* Listened */ |
186 | 172 | ||
187 | if (scrobbler_entry.tracknum > 0) | 173 | char tracknum[11] = { "" }; |
188 | { | 174 | |
189 | ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos), | 175 | if (id->tracknum > 0) |
190 | SCROBBLER_CACHE_LEN, | 176 | snprintf(tracknum, sizeof (tracknum), "%d", id->tracknum); |
191 | "%s\t%s\t%s\t%d\t%d\t%c\t%ld\t%s\n", | 177 | |
192 | scrobbler_entry.artist, | 178 | int ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos), |
193 | scrobbler_entry.album?scrobbler_entry.album:"", | 179 | SCROBBLER_CACHE_LEN, |
194 | scrobbler_entry.title, | 180 | "%s\t%s\t%s\t%s\t%d\t%c\t%ld\t%s\n", |
195 | scrobbler_entry.tracknum, | 181 | id->artist, |
196 | (int)scrobbler_entry.length/1000, | 182 | id->album ?: "", |
197 | rating, | 183 | id->title, |
198 | (long)timestamp, | 184 | tracknum, |
199 | scrobbler_entry.mb_track_id?scrobbler_entry.mb_track_id:""); | 185 | (int)(id->length / 1000), |
200 | } else { | 186 | rating, |
201 | ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos), | 187 | get_timestamp(), |
202 | SCROBBLER_CACHE_LEN, | 188 | id->mb_track_id ?: ""); |
203 | "%s\t%s\t%s\t\t%d\t%c\t%ld\t%s\n", | ||
204 | scrobbler_entry.artist, | ||
205 | scrobbler_entry.album?scrobbler_entry.album:"", | ||
206 | scrobbler_entry.title, | ||
207 | (int)scrobbler_entry.length/1000, | ||
208 | rating, | ||
209 | (long)timestamp, | ||
210 | scrobbler_entry.mb_track_id?scrobbler_entry.mb_track_id:""); | ||
211 | } | ||
212 | 189 | ||
213 | if ( ret >= SCROBBLER_CACHE_LEN ) | 190 | if ( ret >= SCROBBLER_CACHE_LEN ) |
214 | { | 191 | { |
215 | logf("SCROBBLER: entry too long:"); | 192 | logf("SCROBBLER: entry too long:"); |
216 | logf("SCROBBLER: %s", scrobbler_entry.path); | 193 | logf("SCROBBLER: %s", id->path); |
217 | } else { | 194 | } |
195 | else | ||
196 | { | ||
218 | cache_pos++; | 197 | cache_pos++; |
219 | register_storage_idle_func(scrobbler_flush_callback); | 198 | register_storage_idle_func(scrobbler_flush_callback); |
220 | } | 199 | } |
@@ -223,15 +202,11 @@ static void add_to_cache(unsigned long play_length) | |||
223 | 202 | ||
224 | static void scrobbler_change_event(void *data) | 203 | static void scrobbler_change_event(void *data) |
225 | { | 204 | { |
226 | struct mp3entry *id = (struct mp3entry*)data; | 205 | struct mp3entry *id = ((struct track_event *)data)->id3; |
227 | /* add entry using the previous scrobbler_entry and timestamp */ | ||
228 | if (pending) | ||
229 | add_to_cache(audio_prev_elapsed()); | ||
230 | 206 | ||
231 | /* check if track was resumed > %50 played | 207 | /* check if track was resumed > %50 played |
232 | check for blank artist or track name */ | 208 | check for blank artist or track name */ |
233 | if ((id->elapsed > (id->length/2)) || | 209 | if (id->elapsed > id->length / 2 || !id->artist || !id->title) |
234 | (!id->artist ) || (!id->title ) ) | ||
235 | { | 210 | { |
236 | pending = false; | 211 | pending = false; |
237 | logf("SCROBBLER: skipping file %s", id->path); | 212 | logf("SCROBBLER: skipping file %s", id->path); |
@@ -239,81 +214,85 @@ static void scrobbler_change_event(void *data) | |||
239 | else | 214 | else |
240 | { | 215 | { |
241 | logf("SCROBBLER: add pending"); | 216 | logf("SCROBBLER: add pending"); |
242 | copy_mp3entry(&scrobbler_entry, id); | 217 | record_timestamp(); |
243 | #if CONFIG_RTC | ||
244 | timestamp = mktime(get_time()); | ||
245 | #else | ||
246 | timestamp = 0; | ||
247 | #endif | ||
248 | pending = true; | 218 | pending = true; |
249 | } | 219 | } |
250 | } | 220 | } |
251 | 221 | ||
222 | static void scrobbler_finish_event(void *data) | ||
223 | { | ||
224 | struct track_event *te = (struct track_event *)data; | ||
225 | |||
226 | /* add entry using the currently ending track */ | ||
227 | if (pending && (te->flags & TEF_CURRENT) | ||
228 | #if CONFIG_CODEC == SWCODEC | ||
229 | && !(te->flags & TEF_REWIND) | ||
230 | #endif | ||
231 | ) | ||
232 | { | ||
233 | pending = false; | ||
234 | add_to_cache(te->id3); | ||
235 | } | ||
236 | } | ||
237 | |||
252 | int scrobbler_init(void) | 238 | int scrobbler_init(void) |
253 | { | 239 | { |
254 | logf("SCROBBLER: init %d", global_settings.audioscrobbler); | 240 | if (scrobbler_initialised) |
241 | return 1; | ||
255 | 242 | ||
256 | if(!global_settings.audioscrobbler) | 243 | scrobbler_cache = core_alloc("scrobbler", |
257 | return -1; | 244 | SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN); |
258 | 245 | ||
259 | scrobbler_cache = core_alloc("scrobbler", SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN); | ||
260 | if (scrobbler_cache <= 0) | 246 | if (scrobbler_cache <= 0) |
261 | { | 247 | { |
262 | logf("SCROOBLER: OOM"); | 248 | logf("SCROOBLER: OOM"); |
263 | return -1; | 249 | return -1; |
264 | } | 250 | } |
265 | 251 | ||
266 | add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, scrobbler_change_event); | ||
267 | cache_pos = 0; | 252 | cache_pos = 0; |
268 | pending = false; | 253 | pending = false; |
254 | |||
269 | scrobbler_initialised = true; | 255 | scrobbler_initialised = true; |
270 | 256 | ||
257 | add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, scrobbler_change_event); | ||
258 | add_event(PLAYBACK_EVENT_TRACK_FINISH, false, scrobbler_finish_event); | ||
259 | |||
271 | return 1; | 260 | return 1; |
272 | } | 261 | } |
273 | 262 | ||
274 | static void scrobbler_flush_cache(void) | 263 | static void scrobbler_flush_cache(void) |
275 | { | 264 | { |
276 | if (scrobbler_initialised) | ||
277 | { | ||
278 | /* Add any pending entries to the cache */ | 265 | /* Add any pending entries to the cache */ |
279 | if(pending) | 266 | if (pending) |
280 | add_to_cache(audio_prev_elapsed()); | 267 | { |
281 | |||
282 | /* Write the cache to disk if needed */ | ||
283 | if (cache_pos) | ||
284 | write_cache(); | ||
285 | |||
286 | pending = false; | 268 | pending = false; |
269 | if (audio_status()) | ||
270 | add_to_cache(audio_current_track()); | ||
287 | } | 271 | } |
272 | |||
273 | /* Write the cache to disk if needed */ | ||
274 | if (cache_pos) | ||
275 | write_cache(); | ||
288 | } | 276 | } |
289 | 277 | ||
290 | void scrobbler_shutdown(void) | 278 | void scrobbler_shutdown(bool poweroff) |
291 | { | 279 | { |
280 | if (!scrobbler_initialised) | ||
281 | return; | ||
282 | |||
283 | remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event); | ||
284 | remove_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event); | ||
285 | |||
292 | scrobbler_flush_cache(); | 286 | scrobbler_flush_cache(); |
293 | 287 | ||
294 | if (scrobbler_initialised) | 288 | if (!poweroff) |
295 | { | 289 | { |
296 | remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event); | ||
297 | scrobbler_initialised = false; | ||
298 | /* get rid of the buffer */ | 290 | /* get rid of the buffer */ |
299 | core_free(scrobbler_cache); | 291 | core_free(scrobbler_cache); |
300 | scrobbler_cache = 0; | 292 | scrobbler_cache = 0; |
301 | } | 293 | } |
302 | } | ||
303 | 294 | ||
304 | void scrobbler_poweroff(void) | 295 | scrobbler_initialised = false; |
305 | { | ||
306 | if (scrobbler_initialised && pending) | ||
307 | { | ||
308 | if ( audio_status() ) | ||
309 | add_to_cache(audio_current_track()->elapsed); | ||
310 | else | ||
311 | add_to_cache(audio_prev_elapsed()); | ||
312 | |||
313 | /* scrobbler_shutdown is called later, the cache will be written | ||
314 | * make sure the final track isn't added twice when that happens */ | ||
315 | pending = false; | ||
316 | } | ||
317 | } | 296 | } |
318 | 297 | ||
319 | bool scrobbler_is_enabled(void) | 298 | 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 @@ | |||
23 | #define __SCROBBLER_H__ | 23 | #define __SCROBBLER_H__ |
24 | 24 | ||
25 | int scrobbler_init(void); | 25 | int scrobbler_init(void); |
26 | void scrobbler_shutdown(void); | 26 | void scrobbler_shutdown(bool poweroff); |
27 | void scrobbler_poweroff(void); | ||
28 | bool scrobbler_is_enabled(void); | 27 | bool scrobbler_is_enabled(void); |
29 | 28 | ||
30 | #endif /* __SCROBBLER_H__ */ | 29 | #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) | |||
794 | static void tagtree_buffer_event(void *data) | 794 | static void tagtree_buffer_event(void *data) |
795 | { | 795 | { |
796 | struct tagcache_search tcs; | 796 | struct tagcache_search tcs; |
797 | struct mp3entry *id3 = (struct mp3entry*)data; | 797 | struct mp3entry *id3 = ((struct track_event *)data)->id3; |
798 | |||
799 | bool runtimedb = global_settings.runtimedb; | ||
800 | bool autoresume = global_settings.autoresume_enable; | ||
798 | 801 | ||
799 | /* Do not gather data unless proper setting has been enabled. */ | 802 | /* Do not gather data unless proper setting has been enabled. */ |
800 | if (!global_settings.runtimedb && !global_settings.autoresume_enable) | 803 | if (!runtimedb && !autoresume) |
801 | return; | 804 | return; |
802 | 805 | ||
803 | logf("be:%s", id3->path); | 806 | logf("be:%s", id3->path); |
@@ -811,7 +814,7 @@ static void tagtree_buffer_event(void *data) | |||
811 | return; | 814 | return; |
812 | } | 815 | } |
813 | 816 | ||
814 | if (global_settings.runtimedb) | 817 | if (runtimedb) |
815 | { | 818 | { |
816 | id3->playcount = tagcache_get_numeric(&tcs, tag_playcount); | 819 | id3->playcount = tagcache_get_numeric(&tcs, tag_playcount); |
817 | if (!id3->rating) | 820 | if (!id3->rating) |
@@ -824,7 +827,7 @@ static void tagtree_buffer_event(void *data) | |||
824 | } | 827 | } |
825 | 828 | ||
826 | #if CONFIG_CODEC == SWCODEC | 829 | #if CONFIG_CODEC == SWCODEC |
827 | if (global_settings.autoresume_enable) | 830 | if (autoresume) |
828 | { | 831 | { |
829 | /* Load current file resume offset if not already defined (by | 832 | /* Load current file resume offset if not already defined (by |
830 | another resume mechanism) */ | 833 | another resume mechanism) */ |
@@ -846,18 +849,10 @@ static void tagtree_buffer_event(void *data) | |||
846 | 849 | ||
847 | static void tagtree_track_finish_event(void *data) | 850 | static void tagtree_track_finish_event(void *data) |
848 | { | 851 | { |
849 | long lastplayed; | 852 | struct track_event *te = (struct track_event *)data; |
850 | long tagcache_idx; | 853 | struct mp3entry *id3 = te->id3; |
851 | struct mp3entry *id3 = (struct mp3entry*)data; | ||
852 | |||
853 | /* Do not gather data unless proper setting has been enabled. */ | ||
854 | if (!global_settings.runtimedb && !global_settings.autoresume_enable) | ||
855 | { | ||
856 | logf("runtimedb gathering and autoresume not enabled"); | ||
857 | return; | ||
858 | } | ||
859 | 854 | ||
860 | tagcache_idx=id3->tagcache_idx; | 855 | long tagcache_idx = id3->tagcache_idx; |
861 | if (!tagcache_idx) | 856 | if (!tagcache_idx) |
862 | { | 857 | { |
863 | logf("No tagcache index pointer found"); | 858 | logf("No tagcache index pointer found"); |
@@ -865,26 +860,51 @@ static void tagtree_track_finish_event(void *data) | |||
865 | } | 860 | } |
866 | tagcache_idx--; | 861 | tagcache_idx--; |
867 | 862 | ||
868 | /* Don't process unplayed tracks, or tracks interrupted within the | ||
869 | first 15 seconds. */ | ||
870 | if (id3->elapsed == 0 | ||
871 | #if CONFIG_CODEC == SWCODEC /* HWCODEC doesn't have automatic_skip */ | 863 | #if CONFIG_CODEC == SWCODEC /* HWCODEC doesn't have automatic_skip */ |
872 | || (id3->elapsed < 15 * 1000 && !audio_automatic_skip()) | 864 | bool auto_skip = te->flags & TEF_AUTO_SKIP; |
873 | #endif | 865 | #endif |
874 | ) | 866 | bool runtimedb = global_settings.runtimedb; |
867 | bool autoresume = global_settings.autoresume_enable; | ||
868 | |||
869 | /* Don't process unplayed tracks, or tracks interrupted within the | ||
870 | first 15 seconds but always process autoresume point */ | ||
871 | if (runtimedb && (id3->elapsed == 0 | ||
872 | #if CONFIG_CODEC == SWCODEC | ||
873 | || (id3->elapsed < 15 * 1000 && !auto_skip) | ||
874 | #endif | ||
875 | )) | ||
876 | { | ||
877 | logf("not db logging unplayed or skipped track"); | ||
878 | runtimedb = false; | ||
879 | } | ||
880 | |||
881 | #if CONFIG_CODEC == SWCODEC | ||
882 | /* 3s because that is the threshold the WPS uses to rewind instead | ||
883 | of skip backwards */ | ||
884 | if (autoresume && (id3->elapsed == 0 | ||
885 | || (id3->elapsed < 3 * 1000 && !auto_skip))) | ||
886 | { | ||
887 | logf("not logging autoresume"); | ||
888 | autoresume = false; | ||
889 | } | ||
890 | #endif | ||
891 | |||
892 | /* Do not gather data unless proper setting has been enabled and at least | ||
893 | one is still slated to be recorded */ | ||
894 | if (!(runtimedb || autoresume)) | ||
875 | { | 895 | { |
876 | logf("not logging unplayed or skipped track"); | 896 | logf("runtimedb gathering and autoresume not enabled/ignored"); |
877 | return; | 897 | return; |
878 | } | 898 | } |
879 | 899 | ||
880 | lastplayed = tagcache_increase_serial(); | 900 | long lastplayed = tagcache_increase_serial(); |
881 | if (lastplayed < 0) | 901 | if (lastplayed < 0) |
882 | { | 902 | { |
883 | logf("incorrect tc serial:%ld", lastplayed); | 903 | logf("incorrect tc serial:%ld", lastplayed); |
884 | return; | 904 | return; |
885 | } | 905 | } |
886 | 906 | ||
887 | if (global_settings.runtimedb) | 907 | if (runtimedb) |
888 | { | 908 | { |
889 | long playcount; | 909 | long playcount; |
890 | long playtime; | 910 | long playtime; |
@@ -906,10 +926,9 @@ static void tagtree_track_finish_event(void *data) | |||
906 | } | 926 | } |
907 | 927 | ||
908 | #if CONFIG_CODEC == SWCODEC | 928 | #if CONFIG_CODEC == SWCODEC |
909 | if (global_settings.autoresume_enable) | 929 | if (autoresume) |
910 | { | 930 | { |
911 | unsigned long offset | 931 | unsigned long offset = auto_skip ? 0 : id3->offset; |
912 | = audio_automatic_skip() ? 0 : id3->offset; | ||
913 | 932 | ||
914 | tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset); | 933 | tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset); |
915 | 934 | ||
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); | |||
236 | void audio_spdif_set_monitor(int monitor_spdif); | 236 | void audio_spdif_set_monitor(int monitor_spdif); |
237 | #endif /* HAVE_SPDIF_IN */ | 237 | #endif /* HAVE_SPDIF_IN */ |
238 | 238 | ||
239 | unsigned long audio_prev_elapsed(void); | ||
240 | |||
241 | #if CONFIG_CODEC != SWCODEC | ||
242 | /***********************************************************************/ | 239 | /***********************************************************************/ |
243 | /* audio event handling */ | 240 | /* audio event handling */ |
241 | enum track_event_flags | ||
242 | { | ||
243 | TEF_NONE = 0x0, /* no flags are set */ | ||
244 | TEF_CURRENT = 0x1, /* event is for the current track */ | ||
245 | #if CONFIG_CODEC == SWCODEC | ||
246 | TEF_AUTO_SKIP = 0x2, /* event is sent in context of auto skip */ | ||
247 | TEF_REWIND = 0x4, /* interpret as rewind, id3->elapsed is the | ||
248 | position before the seek back to 0 */ | ||
249 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
250 | }; | ||
244 | 251 | ||
252 | struct track_event | ||
253 | { | ||
254 | unsigned int flags; /* combo of enum track_event_flags values */ | ||
255 | struct mp3entry *id3; /* pointer to mp3entry describing track */ | ||
256 | }; | ||
257 | |||
258 | #if CONFIG_CODEC != SWCODEC | ||
245 | /* subscribe to one or more audio event(s) by OR'ing together the desired */ | 259 | /* subscribe to one or more audio event(s) by OR'ing together the desired */ |
246 | /* event IDs (defined below); a handler is called with a solitary event ID */ | 260 | /* event IDs (defined below); a handler is called with a solitary event ID */ |
247 | /* (so switch() is okay) and possibly some useful data (depending on the */ | 261 | /* (so switch() is okay) and possibly some useful data (depending on the */ |