static struct mood *alloc_new_mood(const char *name)
{
- struct mood *m = para_calloc(sizeof(struct mood));
+ struct mood *m = zalloc(sizeof(struct mood));
if (name)
m->name = para_strdup(name);
return m;
PARA_INFO_LOG("opening mood %s\n", mood_name);
ret = mp_init(mood_def.data, mood_def.size, &(*m)->parser_context, errmsg);
osl_close_disk_object(&mood_def);
+ if (ret < 0)
+ destroy_mood(*m);
return ret;
}
* overflows and rounding errors we store the common divisor of the
* correction factors separately.
*/
-static int64_t normalized_value(int64_t x, int64_t n, int64_t sum, int64_t qd)
-{
- if (!n || !qd)
- return 0;
- return 100 * (n * x - sum) / (int64_t)int_sqrt(n) / (int64_t)int_sqrt(qd);
-}
-
static long compute_score(struct afs_info *afsi)
{
- long score = -normalized_value(afsi->num_played, statistics.num,
- statistics.num_played_sum, statistics.num_played_qd);
- score -= normalized_value(afsi->last_played, statistics.num,
- statistics.last_played_sum, statistics.last_played_qd);
- return score / 2;
+ int64_t mean_n, mean_l,score_n, score_l;
+
+ assert(statistics.normalization_divisor > 0);
+ assert(statistics.num > 0);
+ mean_n = statistics.num_played_sum / statistics.num;
+ mean_l = statistics.last_played_sum / statistics.num;
+
+ score_n = -((int64_t)afsi->num_played - mean_n)
+ * statistics.num_played_correction
+ / statistics.normalization_divisor;
+ score_l = -((int64_t)afsi->last_played - mean_l)
+ * statistics.last_played_correction
+ / statistics.normalization_divisor;
+ return (score_n + score_l) / 2;
}
static int add_afs_statistics(const struct osl_row *row)
if (statistics.num >= aa->size) {
aa->size *= 2;
aa->size += 100;
- aa->array = para_realloc(aa->array,
- aa->size * sizeof(struct osl_row *));
+ aa->array = arr_realloc(aa->array, aa->size,
+ sizeof(struct osl_row *));
}
aa->array[statistics.num] = aft_row;
return add_afs_statistics(aft_row);
*
* If there is already an open mood, it will be closed first.
*
- * \return Positive on success, negative on errors. Loading the dummy mood
- * always succeeds.
+ * \return Positive on success, negative on errors.
*
* \sa struct \ref afs_info::last_played, \ref mp_eval_row().
*/
if (mood_name) {
struct mood *m;
struct osl_row *row;
- struct osl_object obj = {
- .data = (char *)mood_name,
- .size = strlen(mood_name) + 1
- };
+ struct osl_object obj;
+
+ if (!*mood_name) {
+ *errmsg = make_message("empty mood name");
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+ }
+ obj.data = (char *)mood_name;
+ obj.size = strlen(mood_name) + 1;
ret = osl(osl_get_row(moods_table, BLOBCOL_NAME, &obj, &row));
if (ret < 0) {
if (errmsg)
if (ret < 0) {
if (errmsg)
*errmsg = make_message("audio file loop failed");
- return ret;
+ goto out;
}
clock_get_realtime(&rnow);
compute_correction_factors(rnow.tv_sec);
ret = statistics.num;
out:
free(aa.array);
+ if (ret < 0)
+ close_current_mood();
return ret;
}
* \param pb Unused.
* \param data Its type depends on the event.
*
- * This function performs actions required due to the occurrence of the given
- * event. Possible actions include reload of the current mood and update of the
- * score of an audio file.
+ * This function updates the score table according to the event that has
+ * occurred. Two actions are possible: (a) reload the current mood, or (b)
+ * add/remove/update the row of the score table which corresponds to the audio
+ * file that has been modified or whose afs info has been changed. It depends
+ * on the type of the event which action (if any) is performed.
+ *
+ * The callbacks of command handlers such as com_add() or com_touch() which
+ * modify the audio file table call this function. The virtual streaming system
+ * also calls this after it has updated the afs info of the file it is about to
+ * stream (the one with the highest score). If the file stays admissible, its
+ * score is recomputed so that a different file is picked next time.
*
* \return Standard.
*/