Get rid of some superfluous single-purpose functions in playback.
* Remove explicit tracking of elapsed time of previous track. * Remove function to obtain auto skip flag. * Most playback events now carry the extra information instead and pass 'struct track_event *' for data. * Tweak scrobbler to use PLAYBACK_EVENT_TRACK_FINISH, which makes it cleaner and removes the struct mp3entry. Change-Id: I500d2abb4056a32646496efc3617406e36811ec5
This commit is contained in:
parent
ffa8626b0c
commit
023f6b6efd
14 changed files with 236 additions and 242 deletions
|
@ -31,21 +31,29 @@
|
||||||
|
|
||||||
/** Playback events **/
|
/** Playback events **/
|
||||||
enum {
|
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),
|
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,
|
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,
|
PLAYBACK_EVENT_CUR_TRACK_READY,
|
||||||
/* Current user track finished */
|
/* Current user track finished
|
||||||
|
data = &(struct track_event){} */
|
||||||
PLAYBACK_EVENT_TRACK_FINISH,
|
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,
|
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,
|
PLAYBACK_EVENT_TRACK_SKIP,
|
||||||
/* Next track medadata was just loaded */
|
/* Next track medadata was just loaded
|
||||||
|
data = &(struct track_event){} */
|
||||||
PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
|
PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
|
||||||
/* Voice is playing: data = &(bool){true|false} */
|
/* Voice is playing
|
||||||
|
data = &(bool){true|false} */
|
||||||
PLAYBACK_EVENT_VOICE_PLAYING,
|
PLAYBACK_EVENT_VOICE_PLAYING,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1190,7 +1190,7 @@ long gui_wps_show(void)
|
||||||
static void track_changed_callback(void *param)
|
static void track_changed_callback(void *param)
|
||||||
{
|
{
|
||||||
struct wps_state *state = skin_get_global_state();
|
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();
|
state->nid3 = audio_next_track();
|
||||||
if (state->id3->cuesheet)
|
if (state->id3->cuesheet)
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,7 +46,7 @@ static const struct dim dim = { .width = 200, .height = 200 };
|
||||||
* notify about track change, and show track info */
|
* notify about track change, and show track info */
|
||||||
static void track_changed_callback(void *param)
|
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;
|
JNIEnv e = *env_ptr;
|
||||||
if (id3)
|
if (id3)
|
||||||
{
|
{
|
||||||
|
@ -108,7 +108,9 @@ static void track_changed_callback(void *param)
|
||||||
* notify about track finishing */
|
* notify about track finishing */
|
||||||
static void track_finished_callback(void *param)
|
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;
|
JNIEnv e = *env_ptr;
|
||||||
e->CallVoidMethod(env_ptr, NotificationManager_instance,
|
e->CallVoidMethod(env_ptr, NotificationManager_instance,
|
||||||
finishNotification);
|
finishNotification);
|
||||||
|
|
|
@ -420,7 +420,8 @@ static void init(void)
|
||||||
global_settings.superbass);
|
global_settings.superbass);
|
||||||
#endif /* CONFIG_CODEC != SWCODEC */
|
#endif /* CONFIG_CODEC != SWCODEC */
|
||||||
|
|
||||||
scrobbler_init();
|
if (global_settings.audioscrobbler)
|
||||||
|
scrobbler_init();
|
||||||
|
|
||||||
audio_init();
|
audio_init();
|
||||||
|
|
||||||
|
@ -700,7 +701,10 @@ static void init(void)
|
||||||
playlist_init();
|
playlist_init();
|
||||||
tree_mem_init();
|
tree_mem_init();
|
||||||
filetype_init();
|
filetype_init();
|
||||||
scrobbler_init();
|
|
||||||
|
if (global_settings.audioscrobbler)
|
||||||
|
scrobbler_init();
|
||||||
|
|
||||||
shortcuts_init();
|
shortcuts_init();
|
||||||
|
|
||||||
#if CONFIG_CODEC != SWCODEC
|
#if CONFIG_CODEC != SWCODEC
|
||||||
|
|
|
@ -157,7 +157,7 @@ static int audioscrobbler_callback(int action,const struct menu_item_ex *this_it
|
||||||
scrobbler_init();
|
scrobbler_init();
|
||||||
|
|
||||||
if(scrobbler_is_enabled() && !global_settings.audioscrobbler)
|
if(scrobbler_is_enabled() && !global_settings.audioscrobbler)
|
||||||
scrobbler_shutdown();
|
scrobbler_shutdown(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return action;
|
return action;
|
||||||
|
|
|
@ -269,8 +269,6 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter)
|
||||||
{
|
{
|
||||||
long msg_id = -1;
|
long msg_id = -1;
|
||||||
|
|
||||||
scrobbler_poweroff();
|
|
||||||
|
|
||||||
#if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
|
#if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
|
||||||
if(!charger_inserted())
|
if(!charger_inserted())
|
||||||
#endif
|
#endif
|
||||||
|
@ -349,6 +347,7 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter)
|
||||||
#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
|
#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
|
||||||
audio_close_recording();
|
audio_close_recording();
|
||||||
#endif
|
#endif
|
||||||
|
scrobbler_shutdown(true);
|
||||||
|
|
||||||
if(global_settings.talk_menu)
|
if(global_settings.talk_menu)
|
||||||
{
|
{
|
||||||
|
|
54
apps/mpeg.c
54
apps/mpeg.c
|
@ -129,8 +129,6 @@ static unsigned int current_track_counter = 0;
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
static void stop_playing(void);
|
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_read_idx = 0;
|
||||||
static int track_write_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;
|
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++)
|
for (i = 0; i < numentries; i++)
|
||||||
{
|
{
|
||||||
/* Send an event to notify that track has finished. */
|
/* 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;
|
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++)
|
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;
|
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);
|
send_nid3_event = (track_write_idx == track_read_idx + 1);
|
||||||
track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK;
|
track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK;
|
||||||
if (send_nid3_event)
|
if (send_nid3_event)
|
||||||
send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL);
|
send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, &track->id3);
|
||||||
debug_tags();
|
debug_tags();
|
||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
|
@ -1093,17 +1099,11 @@ static int new_file(int steps)
|
||||||
|
|
||||||
static void stop_playing(void)
|
static void stop_playing(void)
|
||||||
{
|
{
|
||||||
struct trackdata *track;
|
|
||||||
|
|
||||||
/* Stop the current stream */
|
/* Stop the current stream */
|
||||||
mp3_play_stop();
|
mp3_play_stop();
|
||||||
playing = false;
|
playing = false;
|
||||||
filling = false;
|
filling = false;
|
||||||
|
|
||||||
track = get_trackdata(0);
|
|
||||||
if (track != NULL)
|
|
||||||
prev_track_elapsed = track->id3.elapsed;
|
|
||||||
|
|
||||||
if(mpeg_file >= 0)
|
if(mpeg_file >= 0)
|
||||||
close(mpeg_file);
|
close(mpeg_file);
|
||||||
mpeg_file = -1;
|
mpeg_file = -1;
|
||||||
|
@ -1112,17 +1112,12 @@ static void stop_playing(void)
|
||||||
reset_mp3_buffer();
|
reset_mp3_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_current_track(void) {
|
static void end_current_track(void)
|
||||||
struct trackdata *track;
|
{
|
||||||
|
|
||||||
play_pending = false;
|
play_pending = false;
|
||||||
playing = false;
|
playing = false;
|
||||||
mp3_play_pause(false);
|
mp3_play_pause(false);
|
||||||
|
|
||||||
track = get_trackdata(0);
|
|
||||||
if (track != NULL)
|
|
||||||
prev_track_elapsed = track->id3.elapsed;
|
|
||||||
|
|
||||||
reset_mp3_buffer();
|
reset_mp3_buffer();
|
||||||
remove_all_tags();
|
remove_all_tags();
|
||||||
generate_unbuffer_events();
|
generate_unbuffer_events();
|
||||||
|
@ -1164,9 +1159,6 @@ static void track_change(void)
|
||||||
{
|
{
|
||||||
DEBUGF("Track change\n");
|
DEBUGF("Track change\n");
|
||||||
|
|
||||||
struct trackdata *track = get_trackdata(0);
|
|
||||||
prev_track_elapsed = track->id3.elapsed;
|
|
||||||
|
|
||||||
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
||||||
/* Reset the AVC */
|
/* Reset the AVC */
|
||||||
sound_set_avc(-1);
|
sound_set_avc(-1);
|
||||||
|
@ -1177,17 +1169,15 @@ static void track_change(void)
|
||||||
remove_current_tag();
|
remove_current_tag();
|
||||||
update_playlist();
|
update_playlist();
|
||||||
if (is_playing)
|
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++;
|
current_track_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long audio_prev_elapsed(void)
|
|
||||||
{
|
|
||||||
return prev_track_elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void hexdump(const unsigned char *buf, int len)
|
void hexdump(const unsigned char *buf, int len)
|
||||||
{
|
{
|
||||||
|
@ -1229,7 +1219,8 @@ static void start_playback_if_ready(void)
|
||||||
if (play_pending_track_change)
|
if (play_pending_track_change)
|
||||||
{
|
{
|
||||||
play_pending_track_change = false;
|
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;
|
play_pending = false;
|
||||||
}
|
}
|
||||||
|
@ -2828,11 +2819,6 @@ void audio_play(long offset)
|
||||||
void audio_stop(void)
|
void audio_stop(void)
|
||||||
{
|
{
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
if (playing)
|
|
||||||
{
|
|
||||||
struct trackdata *track = get_trackdata(0);
|
|
||||||
prev_track_elapsed = track->id3.elapsed;
|
|
||||||
}
|
|
||||||
mpeg_stop_done = false;
|
mpeg_stop_done = false;
|
||||||
queue_post(&mpeg_queue, MPEG_STOP, 0);
|
queue_post(&mpeg_queue, MPEG_STOP, 0);
|
||||||
while(!mpeg_stop_done)
|
while(!mpeg_stop_done)
|
||||||
|
|
|
@ -155,13 +155,6 @@ static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */
|
||||||
/* Peeking functions can yield and mess us up */
|
/* Peeking functions can yield and mess us up */
|
||||||
static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/
|
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 **/
|
/** For album art support **/
|
||||||
#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT
|
#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT
|
||||||
#ifdef HAVE_ALBUMART
|
#ifdef HAVE_ALBUMART
|
||||||
|
@ -296,9 +289,8 @@ enum track_skip_type
|
||||||
would work as expected */
|
would work as expected */
|
||||||
|
|
||||||
/* Used to indicate status for the events. Must be separate to satisfy all
|
/* 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
|
clients so the correct metadata is read when sending the change events. */
|
||||||
and also so that it is read correctly outside the events. */
|
static unsigned int track_event_flags = TEF_NONE; /* (A, O-) */
|
||||||
static bool automatic_skip = false; /* (A, O-) */
|
|
||||||
|
|
||||||
/* Pending manual track skip offset */
|
/* Pending manual track skip offset */
|
||||||
static int skip_offset = 0; /* (A, O) */
|
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 */
|
/* Announce the end of playing the current track */
|
||||||
static void audio_playlist_track_finish(void)
|
static void audio_playlist_track_finish(void)
|
||||||
{
|
{
|
||||||
|
@ -1066,12 +1068,8 @@ static void audio_playlist_track_finish(void)
|
||||||
|
|
||||||
if (id3)
|
if (id3)
|
||||||
{
|
{
|
||||||
send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
|
send_track_event(PLAYBACK_EVENT_TRACK_FINISH,
|
||||||
prev_track_elapsed = id3->elapsed;
|
track_event_flags, id3);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
prev_track_elapsed = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,7 +1079,10 @@ static void audio_playlist_track_change(void)
|
||||||
struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3));
|
struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3));
|
||||||
|
|
||||||
if (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();
|
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)
|
static void audio_update_and_announce_next_track(const struct mp3entry *id3_next)
|
||||||
{
|
{
|
||||||
id3_write_locked(NEXTTRACK_ID3, id3_next);
|
id3_write_locked(NEXTTRACK_ID3, id3_next);
|
||||||
send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
|
send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
|
||||||
id3_get(NEXTTRACK_ID3));
|
0, id3_get(NEXTTRACK_ID3));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bring the user current mp3entry up to date and set a new offset for the
|
/* 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;
|
bool resume = !auto_skip;
|
||||||
|
|
||||||
/* Send the "buffer" event to obtain the resume position for the codec */
|
/* 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)
|
if (!resume)
|
||||||
{
|
{
|
||||||
|
@ -1497,7 +1498,7 @@ static bool audio_start_codec(bool auto_skip)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
/* Send the "buffer" event now */
|
/* 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);
|
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
|
/* Send only when the track handles could not all be opened ahead of
|
||||||
time for the user's current track - otherwise everything is ready
|
time for the user's current track - otherwise everything is ready
|
||||||
by the time PLAYBACK_EVENT_TRACK_CHANGE is sent */
|
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
|
#ifdef HAVE_CODEC_BUFFERING
|
||||||
|
@ -2157,7 +2159,7 @@ static void audio_on_finish_load_track(int id3_hid)
|
||||||
buf_read_cuesheet(info->cuesheet_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)
|
if (is_user_current)
|
||||||
{
|
{
|
||||||
|
@ -2356,7 +2358,7 @@ static void audio_on_codec_complete(int status)
|
||||||
|
|
||||||
int trackstat = LOAD_TRACK_OK;
|
int trackstat = LOAD_TRACK_OK;
|
||||||
|
|
||||||
automatic_skip = true;
|
track_event_flags = TEF_AUTO_SKIP;
|
||||||
skip_pending = TRACK_SKIP_AUTO;
|
skip_pending = TRACK_SKIP_AUTO;
|
||||||
|
|
||||||
/* Does this track have an entry allocated? */
|
/* 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);
|
halt_decoding_track(true);
|
||||||
|
|
||||||
automatic_skip = false;
|
track_event_flags = TEF_NONE;
|
||||||
ff_rw_mode = false;
|
ff_rw_mode = false;
|
||||||
|
|
||||||
if (flags & AUDIO_START_RESTART)
|
if (flags & AUDIO_START_RESTART)
|
||||||
|
@ -2595,7 +2597,7 @@ static void audio_stop_playback(void)
|
||||||
audio_playlist_track_finish();
|
audio_playlist_track_finish();
|
||||||
|
|
||||||
skip_pending = TRACK_SKIP_NONE;
|
skip_pending = TRACK_SKIP_NONE;
|
||||||
automatic_skip = false;
|
track_event_flags = TEF_NONE;
|
||||||
|
|
||||||
/* Close all tracks and mark them NULL */
|
/* Close all tracks and mark them NULL */
|
||||||
remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback);
|
remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback);
|
||||||
|
@ -2667,7 +2669,7 @@ static void audio_on_skip(void)
|
||||||
ff_rw_mode = false;
|
ff_rw_mode = false;
|
||||||
|
|
||||||
/* Manual skip */
|
/* Manual skip */
|
||||||
automatic_skip = false;
|
track_event_flags = TEF_NONE;
|
||||||
|
|
||||||
/* If there was an auto skip in progress, there will be residual
|
/* If there was an auto skip in progress, there will be residual
|
||||||
advancement of the playlist and/or track list so compensation will be
|
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;
|
ff_rw_mode = false;
|
||||||
|
|
||||||
/* Manual skip */
|
/* Manual skip */
|
||||||
automatic_skip = false;
|
track_event_flags = TEF_NONE;
|
||||||
|
|
||||||
audio_playlist_track_finish();
|
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 *id3 = id3_get(PLAYING_ID3);
|
||||||
struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
|
struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
|
||||||
|
|
||||||
automatic_skip = false;
|
track_event_flags = TEF_NONE;
|
||||||
|
|
||||||
/* Send event before clobbering the time */
|
/* Send event before clobbering the time if rewinding. */
|
||||||
/* 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? */
|
|
||||||
if (time == 0)
|
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;
|
id3->elapsed = time;
|
||||||
queue_reply(&audio_queue, 1);
|
queue_reply(&audio_queue, 1);
|
||||||
|
@ -3662,14 +3664,6 @@ void playback_release_aa_slot(int slot)
|
||||||
}
|
}
|
||||||
#endif /* HAVE_ALBUMART */
|
#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
|
/* Would normally calculate byte offset from an elapsed time but is not
|
||||||
used on SWCODEC */
|
used on SWCODEC */
|
||||||
int audio_get_file_pos(void)
|
int audio_get_file_pos(void)
|
||||||
|
@ -3677,12 +3671,6 @@ int audio_get_file_pos(void)
|
||||||
return 0;
|
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 */
|
/* Return total file buffer length after accounting for the talk buf */
|
||||||
size_t audio_get_filebuflen(void)
|
size_t audio_get_filebuflen(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,10 +88,6 @@ enum
|
||||||
bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
|
bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
|
||||||
size_t audio_get_filebuflen(void);
|
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);
|
unsigned int playback_status(void);
|
||||||
|
|
||||||
#endif /* _PLAYBACK_H */
|
#endif /* _PLAYBACK_H */
|
||||||
|
|
|
@ -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 char current_track_path[MAX_PATH];
|
||||||
static void rootmenu_track_changed_callback(void* param)
|
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);
|
strlcpy(current_track_path, id3->path, MAX_PATH);
|
||||||
}
|
}
|
||||||
static int browser(void* param)
|
static int browser(void* param)
|
||||||
|
|
195
apps/scrobbler.c
195
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 */
|
/* longest entry I've had is 323, add a safety margin */
|
||||||
#define SCROBBLER_CACHE_LEN 512
|
#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 bool scrobbler_initialised = false;
|
||||||
|
static int scrobbler_cache = 0;
|
||||||
|
static int cache_pos = 0;
|
||||||
|
static bool pending = false;
|
||||||
#if CONFIG_RTC
|
#if CONFIG_RTC
|
||||||
static time_t timestamp;
|
static time_t timestamp;
|
||||||
#else
|
#define BASE_FILENAME ".scrobbler.log"
|
||||||
static unsigned long timestamp;
|
#define HDR_STR_TIMELESS
|
||||||
#endif
|
#define get_timestamp() ((long)timestamp)
|
||||||
|
#define record_timestamp() ((void)(timestamp = mktime(get_time())))
|
||||||
/* Crude work-around for Archos Sims - return a set amount */
|
#else /* !CONFIG_RTC */
|
||||||
#if (CONFIG_CODEC != SWCODEC) && (CONFIG_PLATFORM & PLATFORM_HOSTED)
|
#define HDR_STR_TIMELESS " Timeless"
|
||||||
unsigned long audio_prev_elapsed(void)
|
#define BASE_FILENAME ".scrobbler-timeless.log"
|
||||||
{
|
#define get_timestamp() (0l)
|
||||||
return 120000;
|
#define record_timestamp() ({})
|
||||||
}
|
#endif /* CONFIG_RTC */
|
||||||
#endif
|
|
||||||
|
|
||||||
static void get_scrobbler_filename(char *path, size_t size)
|
static void get_scrobbler_filename(char *path, size_t size)
|
||||||
{
|
{
|
||||||
int used;
|
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 */
|
/* Get location of USB mass storage area */
|
||||||
#ifdef APPLICATION
|
#ifdef APPLICATION
|
||||||
#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
|
#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)
|
#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)
|
#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 */
|
#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) */
|
#endif /* (CONFIG_PLATFORM & PLATFORM_MAEMO) */
|
||||||
|
|
||||||
#else
|
#else
|
||||||
used = snprintf(path, size, "/%s", base_filename);
|
used = snprintf(path, size, "/%s", BASE_FILENAME);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (used >= (int)size)
|
if (used >= (int)size)
|
||||||
|
@ -121,12 +111,9 @@ static void write_cache(void)
|
||||||
if(fd >= 0)
|
if(fd >= 0)
|
||||||
{
|
{
|
||||||
fdprintf(fd, "#AUDIOSCROBBLER/" SCROBBLER_VERSION "\n"
|
fdprintf(fd, "#AUDIOSCROBBLER/" SCROBBLER_VERSION "\n"
|
||||||
"#TZ/UNKNOWN\n"
|
"#TZ/UNKNOWN\n" "#CLIENT/Rockbox "
|
||||||
#if CONFIG_RTC
|
TARGET_NAME SCROBBLER_REVISION
|
||||||
"#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION "\n");
|
HDR_STR_TIMELESS "\n");
|
||||||
#else
|
|
||||||
"#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION " Timeless\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
@ -170,51 +157,43 @@ static void scrobbler_flush_callback(void *data)
|
||||||
write_cache();
|
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 )
|
if ( cache_pos >= SCROBBLER_MAX_CACHE )
|
||||||
write_cache();
|
write_cache();
|
||||||
|
|
||||||
int ret;
|
|
||||||
char rating = 'S'; /* Skipped */
|
char rating = 'S'; /* Skipped */
|
||||||
char* scrobbler_buf = core_get_data(scrobbler_cache);
|
char* scrobbler_buf = core_get_data(scrobbler_cache);
|
||||||
|
|
||||||
logf("SCROBBLER: add_to_cache[%d]", cache_pos);
|
logf("SCROBBLER: add_to_cache[%d]", cache_pos);
|
||||||
|
|
||||||
if ( play_length > (scrobbler_entry.length/2) )
|
if (id->elapsed > id->length / 2)
|
||||||
rating = 'L'; /* Listened */
|
rating = 'L'; /* Listened */
|
||||||
|
|
||||||
if (scrobbler_entry.tracknum > 0)
|
char tracknum[11] = { "" };
|
||||||
{
|
|
||||||
ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos),
|
if (id->tracknum > 0)
|
||||||
SCROBBLER_CACHE_LEN,
|
snprintf(tracknum, sizeof (tracknum), "%d", id->tracknum);
|
||||||
"%s\t%s\t%s\t%d\t%d\t%c\t%ld\t%s\n",
|
|
||||||
scrobbler_entry.artist,
|
int ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos),
|
||||||
scrobbler_entry.album?scrobbler_entry.album:"",
|
SCROBBLER_CACHE_LEN,
|
||||||
scrobbler_entry.title,
|
"%s\t%s\t%s\t%s\t%d\t%c\t%ld\t%s\n",
|
||||||
scrobbler_entry.tracknum,
|
id->artist,
|
||||||
(int)scrobbler_entry.length/1000,
|
id->album ?: "",
|
||||||
rating,
|
id->title,
|
||||||
(long)timestamp,
|
tracknum,
|
||||||
scrobbler_entry.mb_track_id?scrobbler_entry.mb_track_id:"");
|
(int)(id->length / 1000),
|
||||||
} else {
|
rating,
|
||||||
ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos),
|
get_timestamp(),
|
||||||
SCROBBLER_CACHE_LEN,
|
id->mb_track_id ?: "");
|
||||||
"%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:"");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ret >= SCROBBLER_CACHE_LEN )
|
if ( ret >= SCROBBLER_CACHE_LEN )
|
||||||
{
|
{
|
||||||
logf("SCROBBLER: entry too long:");
|
logf("SCROBBLER: entry too long:");
|
||||||
logf("SCROBBLER: %s", scrobbler_entry.path);
|
logf("SCROBBLER: %s", id->path);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
cache_pos++;
|
cache_pos++;
|
||||||
register_storage_idle_func(scrobbler_flush_callback);
|
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)
|
static void scrobbler_change_event(void *data)
|
||||||
{
|
{
|
||||||
struct mp3entry *id = (struct mp3entry*)data;
|
struct mp3entry *id = ((struct track_event *)data)->id3;
|
||||||
/* add entry using the previous scrobbler_entry and timestamp */
|
|
||||||
if (pending)
|
|
||||||
add_to_cache(audio_prev_elapsed());
|
|
||||||
|
|
||||||
/* check if track was resumed > %50 played
|
/* check if track was resumed > %50 played
|
||||||
check for blank artist or track name */
|
check for blank artist or track name */
|
||||||
if ((id->elapsed > (id->length/2)) ||
|
if (id->elapsed > id->length / 2 || !id->artist || !id->title)
|
||||||
(!id->artist ) || (!id->title ) )
|
|
||||||
{
|
{
|
||||||
pending = false;
|
pending = false;
|
||||||
logf("SCROBBLER: skipping file %s", id->path);
|
logf("SCROBBLER: skipping file %s", id->path);
|
||||||
|
@ -239,81 +214,85 @@ static void scrobbler_change_event(void *data)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logf("SCROBBLER: add pending");
|
logf("SCROBBLER: add pending");
|
||||||
copy_mp3entry(&scrobbler_entry, id);
|
record_timestamp();
|
||||||
#if CONFIG_RTC
|
|
||||||
timestamp = mktime(get_time());
|
|
||||||
#else
|
|
||||||
timestamp = 0;
|
|
||||||
#endif
|
|
||||||
pending = true;
|
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)
|
int scrobbler_init(void)
|
||||||
{
|
{
|
||||||
logf("SCROBBLER: init %d", global_settings.audioscrobbler);
|
if (scrobbler_initialised)
|
||||||
|
return 1;
|
||||||
|
|
||||||
if(!global_settings.audioscrobbler)
|
scrobbler_cache = core_alloc("scrobbler",
|
||||||
return -1;
|
SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
|
||||||
|
|
||||||
scrobbler_cache = core_alloc("scrobbler", SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
|
|
||||||
if (scrobbler_cache <= 0)
|
if (scrobbler_cache <= 0)
|
||||||
{
|
{
|
||||||
logf("SCROOBLER: OOM");
|
logf("SCROOBLER: OOM");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, scrobbler_change_event);
|
|
||||||
cache_pos = 0;
|
cache_pos = 0;
|
||||||
pending = false;
|
pending = false;
|
||||||
|
|
||||||
scrobbler_initialised = true;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scrobbler_flush_cache(void)
|
static void scrobbler_flush_cache(void)
|
||||||
{
|
{
|
||||||
if (scrobbler_initialised)
|
|
||||||
{
|
|
||||||
/* Add any pending entries to the cache */
|
/* Add any pending entries to the cache */
|
||||||
if(pending)
|
if (pending)
|
||||||
add_to_cache(audio_prev_elapsed());
|
{
|
||||||
|
|
||||||
/* Write the cache to disk if needed */
|
|
||||||
if (cache_pos)
|
|
||||||
write_cache();
|
|
||||||
|
|
||||||
pending = false;
|
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();
|
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 */
|
/* get rid of the buffer */
|
||||||
core_free(scrobbler_cache);
|
core_free(scrobbler_cache);
|
||||||
scrobbler_cache = 0;
|
scrobbler_cache = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void scrobbler_poweroff(void)
|
scrobbler_initialised = false;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scrobbler_is_enabled(void)
|
bool scrobbler_is_enabled(void)
|
||||||
|
|
|
@ -23,8 +23,7 @@
|
||||||
#define __SCROBBLER_H__
|
#define __SCROBBLER_H__
|
||||||
|
|
||||||
int scrobbler_init(void);
|
int scrobbler_init(void);
|
||||||
void scrobbler_shutdown(void);
|
void scrobbler_shutdown(bool poweroff);
|
||||||
void scrobbler_poweroff(void);
|
|
||||||
bool scrobbler_is_enabled(void);
|
bool scrobbler_is_enabled(void);
|
||||||
|
|
||||||
#endif /* __SCROBBLER_H__ */
|
#endif /* __SCROBBLER_H__ */
|
||||||
|
|
|
@ -794,10 +794,13 @@ static int compare(const void *p1, const void *p2)
|
||||||
static void tagtree_buffer_event(void *data)
|
static void tagtree_buffer_event(void *data)
|
||||||
{
|
{
|
||||||
struct tagcache_search tcs;
|
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. */
|
/* Do not gather data unless proper setting has been enabled. */
|
||||||
if (!global_settings.runtimedb && !global_settings.autoresume_enable)
|
if (!runtimedb && !autoresume)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
logf("be:%s", id3->path);
|
logf("be:%s", id3->path);
|
||||||
|
@ -811,7 +814,7 @@ static void tagtree_buffer_event(void *data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global_settings.runtimedb)
|
if (runtimedb)
|
||||||
{
|
{
|
||||||
id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
|
id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
|
||||||
if (!id3->rating)
|
if (!id3->rating)
|
||||||
|
@ -824,7 +827,7 @@ static void tagtree_buffer_event(void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
if (global_settings.autoresume_enable)
|
if (autoresume)
|
||||||
{
|
{
|
||||||
/* Load current file resume offset if not already defined (by
|
/* Load current file resume offset if not already defined (by
|
||||||
another resume mechanism) */
|
another resume mechanism) */
|
||||||
|
@ -846,18 +849,10 @@ static void tagtree_buffer_event(void *data)
|
||||||
|
|
||||||
static void tagtree_track_finish_event(void *data)
|
static void tagtree_track_finish_event(void *data)
|
||||||
{
|
{
|
||||||
long lastplayed;
|
struct track_event *te = (struct track_event *)data;
|
||||||
long tagcache_idx;
|
struct mp3entry *id3 = te->id3;
|
||||||
struct mp3entry *id3 = (struct mp3entry*)data;
|
|
||||||
|
|
||||||
/* Do not gather data unless proper setting has been enabled. */
|
long tagcache_idx = id3->tagcache_idx;
|
||||||
if (!global_settings.runtimedb && !global_settings.autoresume_enable)
|
|
||||||
{
|
|
||||||
logf("runtimedb gathering and autoresume not enabled");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tagcache_idx=id3->tagcache_idx;
|
|
||||||
if (!tagcache_idx)
|
if (!tagcache_idx)
|
||||||
{
|
{
|
||||||
logf("No tagcache index pointer found");
|
logf("No tagcache index pointer found");
|
||||||
|
@ -865,26 +860,51 @@ static void tagtree_track_finish_event(void *data)
|
||||||
}
|
}
|
||||||
tagcache_idx--;
|
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 */
|
#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
|
#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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastplayed = tagcache_increase_serial();
|
long lastplayed = tagcache_increase_serial();
|
||||||
if (lastplayed < 0)
|
if (lastplayed < 0)
|
||||||
{
|
{
|
||||||
logf("incorrect tc serial:%ld", lastplayed);
|
logf("incorrect tc serial:%ld", lastplayed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global_settings.runtimedb)
|
if (runtimedb)
|
||||||
{
|
{
|
||||||
long playcount;
|
long playcount;
|
||||||
long playtime;
|
long playtime;
|
||||||
|
@ -906,10 +926,9 @@ static void tagtree_track_finish_event(void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
if (global_settings.autoresume_enable)
|
if (autoresume)
|
||||||
{
|
{
|
||||||
unsigned long offset
|
unsigned long offset = auto_skip ? 0 : id3->offset;
|
||||||
= audio_automatic_skip() ? 0 : id3->offset;
|
|
||||||
|
|
||||||
tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset);
|
tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset);
|
||||||
|
|
||||||
|
|
|
@ -236,12 +236,26 @@ int audio_get_spdif_sample_rate(void);
|
||||||
void audio_spdif_set_monitor(int monitor_spdif);
|
void audio_spdif_set_monitor(int monitor_spdif);
|
||||||
#endif /* HAVE_SPDIF_IN */
|
#endif /* HAVE_SPDIF_IN */
|
||||||
|
|
||||||
unsigned long audio_prev_elapsed(void);
|
|
||||||
|
|
||||||
#if CONFIG_CODEC != SWCODEC
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
/* audio event handling */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* (so switch() is okay) and possibly some useful data (depending on the */
|
||||||
|
|
Loading…
Reference in a new issue