return write_all(server_socket, buf, 8);
}
-static int activate_mood_or_playlist(const char *arg, int *num_admissible,
- char **errmsg)
+static int activate_mood_or_playlist(const char *arg, struct para_buffer *pb)
{
enum play_mode mode;
int ret;
+ char *msg;
if (!arg) {
+ ret = mood_switch(NULL, &msg);
+ mode = PLAY_MODE_MOOD;
+ } else if (!strncmp(arg, "p/", 2)) {
+ ret = playlist_open(arg + 2, &msg);
+ mode = PLAY_MODE_PLAYLIST;
+ } else if (!strncmp(arg, "m/", 2)) {
+ ret = mood_switch(arg + 2, &msg);
mode = PLAY_MODE_MOOD;
- ret = mood_switch(NULL, errmsg);
- if (ret < 0) {
- if (num_admissible)
- *num_admissible = 0;
- return ret;
- }
} else {
- if (!strncmp(arg, "p/", 2)) {
- ret = playlist_open(arg + 2, errmsg);
- mode = PLAY_MODE_PLAYLIST;
- } else if (!strncmp(arg, "m/", 2)) {
- ret = mood_switch(arg + 2, errmsg);
- mode = PLAY_MODE_MOOD;
- } else {
- if (errmsg)
- *errmsg = make_message("%s: parse error", arg);
- return -ERRNO_TO_PARA_ERROR(EINVAL);
- }
- if (ret < 0)
- return ret;
+ ret = -ERRNO_TO_PARA_ERROR(EINVAL);
+ msg = make_message("%s: parse error", arg);
}
- if (num_admissible)
- *num_admissible = ret;
+ if (pb)
+ para_printf(pb, "%s", msg);
+ free(msg);
+ if (ret < 0)
+ return ret;
current_play_mode = mode;
/*
* We get called with arg == current_mop from the signal dispatcher
{
const struct lls_command *cmd = SERVER_CMD_CMD_PTR(SELECT);
const char *arg;
- int num_admissible, ret;
- char *errmsg;
+ int ret;
ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr);
assert(ret >= 0);
close_current_mood();
else
playlist_close();
- ret = activate_mood_or_playlist(arg, &num_admissible, &errmsg);
+ ret = activate_mood_or_playlist(arg, &aca->pbout);
if (ret >= 0)
- goto out;
+ goto free_lpr;
/* ignore subsequent errors (but log them) */
- para_printf(&aca->pbout, "%s\n", errmsg);
- free(errmsg);
- para_printf(&aca->pbout, "could not activate %s\n", arg);
if (current_mop && strcmp(current_mop, arg) != 0) {
int ret2;
para_printf(&aca->pbout, "switching back to %s\n", current_mop);
- ret2 = activate_mood_or_playlist(current_mop, &num_admissible,
- &errmsg);
+ ret2 = activate_mood_or_playlist(current_mop, &aca->pbout);
if (ret2 >= 0)
- goto out;
- para_printf(&aca->pbout, "%s\n", errmsg);
- free(errmsg);
+ goto free_lpr;
para_printf(&aca->pbout, "could not reactivate %s: %s\n",
current_mop, para_strerror(-ret2));
}
- para_printf(&aca->pbout, "activating dummy mood\n");
- activate_mood_or_playlist(NULL, &num_admissible, NULL);
-out:
- para_printf(&aca->pbout, "activated %s (%d admissible file%s)\n",
- current_mop? current_mop : "dummy mood", num_admissible,
- num_admissible == 1? "" : "s");
+ activate_mood_or_playlist(NULL, &aca->pbout);
free_lpr:
lls_free_parse_result(aca->lpr, cmd);
return ret;
static void init_admissible_files(const char *arg)
{
- int ret = activate_mood_or_playlist(arg, NULL, NULL);
+ int ret = activate_mood_or_playlist(arg, NULL);
if (ret < 0) {
PARA_WARNING_LOG("could not activate %s: %s\n", arg,
para_strerror(-ret));
if (arg)
- activate_mood_or_playlist(NULL, NULL, NULL);
+ activate_mood_or_playlist(NULL, NULL);
}
}
void free_status_items(void);
/* mood */
-int mood_switch(const char *mood_name, char **errmsg);
+int mood_switch(const char *mood_name, char **msg);
void close_current_mood(void);
int mood_check_callback(struct afs_callback_arg *aca);
/* playlist */
-int playlist_open(const char *name, char **errmsg);
+int playlist_open(const char *name, char **msg);
void playlist_close(void);
int playlist_check_callback(struct afs_callback_arg *aca);
}
/* sse: seconds since epoch. */
-static void log_statistics(struct afs_statistics *stats, int64_t sse)
+static char *get_statistics(struct mood *m, int64_t sse)
{
- unsigned n = stats->num;
+ unsigned n = m->stats.num;
int mean_days, sigma_days;
- if (!n) {
- PARA_WARNING_LOG("no admissible files\n");
- return;
- }
- PARA_NOTICE_LOG("%u admissible files\n", stats->num);
- mean_days = (sse - stats->last_played_sum / n) / 3600 / 24;
- sigma_days = int_sqrt(stats->last_played_qd / n) / 3600 / 24;
- PARA_NOTICE_LOG("last_played mean/sigma: %d/%d days\n", mean_days, sigma_days);
- PARA_NOTICE_LOG("num_played mean/sigma: %" PRId64 "/%" PRIu64 "\n",
- stats->num_played_sum / n,
- int_sqrt(stats->num_played_qd / n));
- PARA_NOTICE_LOG("num_played correction factor: %" PRId64 "\n",
- stats->num_played_correction);
- PARA_NOTICE_LOG("last_played correction factor: %" PRId64 "\n",
- stats->last_played_correction);
- PARA_NOTICE_LOG("normalization divisor: %" PRId64 "\n",
- stats->normalization_divisor);
+ mean_days = (sse - m->stats.last_played_sum / n) / 3600 / 24;
+ sigma_days = int_sqrt(m->stats.last_played_qd / n) / 3600 / 24;
+ return make_message(
+ "loaded mood %s (%u files)\n"
+ "last_played mean/sigma: %d/%d days\n"
+ "num_played mean/sigma: %" PRId64 "/%" PRIu64 "\n"
+ ,
+ m->name? m->name : "(dummy)",
+ n,
+ mean_days, sigma_days,
+ m->stats.num_played_sum / n,
+ int_sqrt(m->stats.num_played_qd / n)
+ );
}
/**
/**
* Change the current mood.
*
+ * If there is already an open mood, it will be closed first.
+ *
* \param mood_name The name of the mood to open.
- * \param errmsg Error description is returned here.
+ * \param msg Error message or mood info is returned here.
*
* If \a mood_name is \a NULL, load the dummy mood that accepts every audio file
* and uses a scoring method based only on the \a last_played information.
*
- * The errmsg pointer may be NULL, in which case no error message will be
- * returned. If a non-NULL pointer is given, the caller must free *errmsg.
+ * If the message pointer is not NULL, a suitable message is returned there in
+ * all cases. The caller must free this string.
*
- * If there is already an open mood, it will be closed first.
- *
- * \return Positive on success, negative on errors.
+ * \return The number of admissible files on success, negative on errors. It is
+ * not considered an error if no files are admissible.
*
* \sa struct \ref afs_info::last_played, \ref mp_eval_row().
*/
-int mood_switch(const char *mood_name, char **errmsg)
+int mood_switch(const char *mood_name, char **msg)
{
int i, ret;
struct admissible_array aa = {.size = 0};
struct timeval rnow;
if (mood_name) {
- ret = init_mood_parser(mood_name, &aa.m, errmsg);
+ ret = init_mood_parser(mood_name, &aa.m, msg);
if (ret < 0)
return ret;
} else /* load dummy mood */
PARA_NOTICE_LOG("computing statistics of admissible files\n");
ret = audio_file_loop(&aa, add_if_admissible);
if (ret < 0) {
- if (errmsg)
- *errmsg = make_message("audio file loop failed");
+ if (msg) /* false if we are called via the event handler */
+ *msg = make_message("audio file loop failed\n");
goto out;
}
clock_get_realtime(&rnow);
compute_correction_factors(rnow.tv_sec, &aa.m->stats);
- log_statistics(&aa.m->stats, rnow.tv_sec);
+ if (aa.m->stats.num == 0) {
+ if (msg)
+ *msg = make_message("no admissible files\n");
+ ret = 0;
+ goto out;
+ }
for (i = 0; i < aa.m->stats.num; i++) {
ret = add_to_score_table(aa.array[i], &aa.m->stats);
if (ret < 0) {
- if (errmsg)
- *errmsg = make_message(
- "could not add row to score table");
+ if (msg)
+ *msg = make_message(
+ "could not add row to score table\n");
goto out;
}
}
/* success */
+ if (msg)
+ *msg = get_statistics(aa.m, rnow.tv_sec);
+ ret = aa.m->stats.num;
close_current_mood();
current_mood = aa.m;
- PARA_NOTICE_LOG("loaded mood %s\n", mood_name? mood_name : "(dummy)");
- ret = aa.m->stats.num;
out:
free(aa.array);
if (ret < 0)
* corresponding row of the audio file table is added to the score table.
*
* \param name The name of the playlist to open.
- * \param errmsg To be sent to the client (if called via select command).
+ * \param msg Error message or playlist info is returned here.
*
* \return The length of the loaded playlist on success, negative error code
* else. Files which are listed in the playlist, but are not contained in the
* database are ignored. This is not considered an error.
*/
-int playlist_open(const char *name, char **errmsg)
+int playlist_open(const char *name, char **msg)
{
int ret;
struct playlist_info *playlist = ¤t_playlist;
ret = pl_get_def_by_name(name, &playlist_def);
if (ret < 0) {
- if (errmsg)
- *errmsg = make_message("could not read playlist %s",
- name);
+ *msg = make_message("could not read playlist %s\n", name);
return ret;
}
playlist_close();
if (!playlist->length)
goto err;
playlist->name = para_strdup(name);
- PARA_NOTICE_LOG("loaded playlist %s (%u files)\n", playlist->name,
+ *msg = make_message("loaded playlist %s (%u files)\n", playlist->name,
playlist->length);
/* success */
return current_playlist.length;
err:
PARA_NOTICE_LOG("unable to load playlist %s\n", name);
- if (errmsg)
- *errmsg = make_message("unable to load playlist %s: %s\n",
- name, para_strerror(-ret));
+ *msg = make_message("unable to load playlist %s\n", name);
return ret;
}