/*
- * Copyright (C) 2007-2013 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2007 Andre Noll <maan@tuebingen.mpg.de>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
#include "ipc.h"
#include "mm.h"
#include "sideband.h"
+#include "mood.h"
/**
* Contains statistical data of the currently admissible audio files.
int64_t num_played_sum;
/** Sum of last played times over all admissible files. */
int64_t last_played_sum;
- /** Quadratic deviation of num played time. */
+ /** Quadratic deviation of num played count. */
int64_t num_played_qd;
/** Quadratic deviation of last played time. */
int64_t last_played_qd;
int ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def);
if (ret < 0) {
- para_printf(pb, "failed to get mood definition: %s\n",
- para_strerror(-ret));
+ para_printf(pb, "cannot read mood\n");
return ret;
}
if (!*mood_name) /* ignore dummy row */
goto out;
- ret = para_printf(pb, "checking mood %s...\n", mood_name);
- if (ret < 0)
- goto out;
+ para_printf(pb, "checking mood %s...\n", mood_name);
ret = for_each_line(FELF_READ_ONLY, mood_def.data, mood_def.size,
parse_mood_line, &mlpd);
if (ret < 0)
- para_printf(pb, "%s line %u: %s\n", mood_name, mlpd.line_num,
- para_strerror(-ret));
+ para_printf(pb, "mood %s: error in line %u: %s\n", mood_name,
+ mlpd.line_num, para_strerror(-ret));
+ ret = 1; /* don't fail the loop on invalid mood definitions */
out:
osl_close_disk_object(&mood_def);
return ret;
/**
* Check all moods for syntax errors.
*
- * \param fd The afs socket.
- * \param query Unused.
+ * \param aca Only ->pbout is used for diagnostics.
+ *
+ * \return Negative on fatal errors. Inconsistent mood definitions are not
+ * considered an error.
*/
-void mood_check_callback(int fd, __a_unused const struct osl_object *query)
+int mood_check_callback(struct afs_callback_arg *aca)
{
- struct para_buffer pb = {
- .max_size = shm_get_shmmax(),
- .private_data = &(struct afs_max_size_handler_data) {
- .fd = fd,
- .band = SBD_OUTPUT
- },
- .max_size_handler = afs_max_size_handler
- };
-
- int ret = para_printf(&pb, "checking moods...\n");
- if (ret < 0)
- return;
- osl_rbtree_loop(moods_table, BLOBCOL_ID, &pb,
- check_mood);
- if (pb.offset)
- pass_buffer_as_shm(fd, SBD_OUTPUT, pb.buf, pb.offset);
- free(pb.buf);
+ para_printf(&aca->pbout, "checking moods...\n");
+ return osl(osl_rbtree_loop(moods_table, BLOBCOL_ID, &aca->pbout,
+ check_mood));
}
static int64_t normalized_value(int64_t x, int64_t n, int64_t sum, int64_t qd)
return 100 * (n * x - sum) / (int64_t)int_sqrt(n * qd);
}
-static long compute_num_played_score(struct afs_info *afsi)
+static long compute_score(struct afs_info *afsi, long mood_score)
{
- return -normalized_value(afsi->num_played, statistics.num,
+ mood_score -= normalized_value(afsi->num_played, statistics.num,
statistics.num_played_sum, statistics.num_played_qd);
-}
-
-static long compute_last_played_score(struct afs_info *afsi)
-{
- return -normalized_value(afsi->last_played, statistics.num,
+ mood_score -= normalized_value(afsi->last_played, statistics.num,
statistics.last_played_sum, statistics.last_played_qd);
-}
-
-static long compute_dynamic_score(const struct osl_row *aft_row)
-{
- struct afs_info afsi;
- int64_t score, nscore = 0, lscore = 0;
- int ret;
-
- ret = get_afsi_of_row(aft_row, &afsi);
- if (ret < 0)
- return -100;
- nscore = compute_num_played_score(&afsi);
- lscore = compute_last_played_score(&afsi);
- score = nscore + lscore;
- return score;
+ return mood_score / 3;
}
static int add_afs_statistics(const struct osl_row *row)
/**
* Structure used during mood_open().
*
- * At mood open time, we look at each file in the audio file table in order to
- * determine whether it is admissible. If a file happens to be admissible, its
- * mood score is computed by calling each relevant mood_score_function. Next,
- * we update the afs_statistics and add a struct admissible_file_info to a
- * temporary array.
+ * At mood open time we determine the set of admissible files for the given
+ * mood. The mood score of each admissible file is computed by adding up all
+ * mood item scores. Next, we update the afs statistics and append a struct
+ * admissible_file_info to a temporary array.
*
- * If all files have been processed that way, the final score of each
+ * When all files have been processed in this way, the final score of each
* admissible file is computed by adding the dynamic score (which depends on
- * the afs_statistics) to the mood score. Finally, all audio files in the
- * array are added to the score table and the admissible array is freed.
+ * the afs_statistics and the current time) to the mood score. Finally, all
+ * audio files in the temporary array are added to the score table and the
+ * array is freed.
*
* \sa mood_method, admissible_array.
*/
static int add_to_score_table(const struct osl_row *aft_row, long mood_score)
{
- long score = (compute_dynamic_score(aft_row) + mood_score) / 3;
+ long score;
+ struct afs_info afsi;
+ int ret = get_afsi_of_row(aft_row, &afsi);
+
+ if (ret < 0)
+ return ret;
+ score = compute_score(&afsi, mood_score);
return score_add(aft_row, score);
}
if (ret < 0)
return ret;
}
- score += compute_num_played_score(&afsi);
- score += compute_last_played_score(&afsi);
- score /= 3;
+ score = compute_score(&afsi, score);
PARA_DEBUG_LOG("score: %li\n", score);
percent = (score + 100) / 3;
if (percent > 100)
if (ret < 0)
return ret;
log_statistics();
- PARA_INFO_LOG("%d admissible files \n", statistics.num);
+ PARA_INFO_LOG("%d admissible files\n", statistics.num);
for (i = 0; i < statistics.num; i++) {
struct admissible_file_info *a = aa.array + i;
ret = add_to_score_table(a->aft_row, a->score);
int ret;
char *mood_name = NULL;
+ ret = clear_score_table();
+ if (ret < 0)
+ return ret;
if (!current_mood)
return 1;
PARA_NOTICE_LOG("reloading %s\n", current_mood->name?
int moods_event_handler(enum afs_events event, __a_unused struct para_buffer *pb,
void *data)
{
- int ret;
-
if (!current_mood)
return 0;
switch (event) {
case BLOB_ADD:
if (data == moods_table || data == playlists_table)
return 1; /* no reload necessary for these */
- ret = clear_score_table();
- if (ret < 0)
- PARA_CRIT_LOG("clear score table returned %s\n",
- para_strerror(-ret));
return reload_current_mood();
/* these also require reload of the score table */
case ATTRIBUTE_ADD: