aft: Update status items on afs events.
authorAndre Noll <maan@tuebingen.mpg.de>
Mon, 22 Dec 2014 18:05:38 +0000 (18:05 +0000)
committerAndre Noll <maan@tuebingen.mpg.de>
Mon, 30 Mar 2015 21:40:58 +0000 (21:40 +0000)
When a paraslash command changes the afs or afh info structures of the
current audio file, for example by re-adding the file with modified
meta tags, the stat output still reports the old values. With this
patch applied, the status items are updated immediately.

This is achieved by letting aft.c honor the AFSI_CHANGE and AFHI_CHANGE
events. If the audio file which triggered the event is the one
currently being streamed, the event handler recreates the status items.
We need two new global static variables in aft.c to track the row of
the audio file table which corresponds to the current file.

aft.c

diff --git a/aft.c b/aft.c
index 517c972..0e86b12 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -1040,7 +1040,10 @@ out:
        return ret;
 }
 
-static int make_status_items(struct ls_data *d)
+static struct ls_data status_item_ls_data;
+static struct osl_row *current_aft_row;
+
+static int make_status_items(void)
 {
        struct ls_options opts = {
                .flags = LS_FLAG_FULL_PATH | LS_FLAG_ADMISSIBLE_ONLY,
@@ -1051,7 +1054,7 @@ static int make_status_items(struct ls_data *d)
        int ret;
 
        time(&current_time);
-       ret = print_list_item(d, &opts, &pb, current_time);
+       ret = print_list_item(&status_item_ls_data, &opts, &pb, current_time);
        if (ret < 0)
                return ret;
        free(status_items);
@@ -1059,7 +1062,7 @@ static int make_status_items(struct ls_data *d)
        memset(&pb, 0, sizeof(pb));
        pb.max_size = shm_get_shmmax() - 1;
        pb.flags = PBF_SIZE_PREFIX;
-       ret = print_list_item(d, &opts, &pb, current_time);
+       ret = print_list_item(&status_item_ls_data, &opts, &pb, current_time);
        if (ret < 0) {
                free(status_items);
                status_items = NULL;
@@ -1083,70 +1086,70 @@ static int make_status_items(struct ls_data *d)
  */
 int open_and_update_audio_file(struct audio_file_data *afd)
 {
-       struct osl_row *aft_row;
        unsigned char file_hash[HASH_SIZE];
        struct osl_object afsi_obj;
        struct afs_info new_afsi;
        int ret;
        struct afsi_change_event_data aced;
        struct osl_object map, chunk_table_obj;
-       struct ls_data d;
+       struct ls_data *d = &status_item_ls_data;
 again:
-       ret = score_get_best(&aft_row, &d.score);
+       ret = score_get_best(&current_aft_row, &d->score);
        if (ret < 0)
                return ret;
-       ret = get_hash_of_row(aft_row, &d.hash);
+       ret = get_hash_of_row(current_aft_row, &d->hash);
        if (ret < 0)
                return ret;
-       ret = get_audio_file_path_of_row(aft_row, &d.path);
+       ret = get_audio_file_path_of_row(current_aft_row, &d->path);
        if (ret < 0)
                return ret;
-       PARA_NOTICE_LOG("%s\n", d.path);
-       ret = get_afsi_object_of_row(aft_row, &afsi_obj);
+       PARA_NOTICE_LOG("%s\n", d->path);
+       ret = get_afsi_object_of_row(current_aft_row, &afsi_obj);
        if (ret < 0)
                return ret;
-       ret = load_afsi(&d.afsi, &afsi_obj);
+       ret = load_afsi(&d->afsi, &afsi_obj);
        if (ret < 0)
                return ret;
-       ret = get_afhi_of_row(aft_row, &afd->afhi);
+       ret = get_afhi_of_row(current_aft_row, &afd->afhi);
        if (ret < 0)
                return ret;
-       d.afhi = afd->afhi;
-       d.afhi.chunk_table = afd->afhi.chunk_table = NULL;
-       ret = osl(osl_open_disk_object(audio_file_table, aft_row,
+       d->afhi = afd->afhi;
+       d->afhi.chunk_table = afd->afhi.chunk_table = NULL;
+       ret = osl(osl_open_disk_object(audio_file_table, current_aft_row,
                AFTCOL_CHUNKS, &chunk_table_obj));
        if (ret < 0)
                return ret;
-       ret = mmap_full_file(d.path, O_RDONLY, &map.data, &map.size, &afd->fd);
+       ret = mmap_full_file(d->path, O_RDONLY, &map.data, &map.size, &afd->fd);
        if (ret < 0)
                goto err;
        hash_function(map.data, map.size, file_hash);
-       ret = hash_compare(file_hash, d.hash);
+       ret = hash_compare(file_hash, d->hash);
        para_munmap(map.data, map.size);
        if (ret) {
                ret = -E_HASH_MISMATCH;
                goto err;
        }
-       new_afsi = d.afsi;
+       new_afsi = d->afsi;
        new_afsi.num_played++;
        new_afsi.last_played = time(NULL);
        save_afsi(&new_afsi, &afsi_obj); /* in-place update */
 
-       afd->audio_format_id = d.afsi.audio_format_id;
+       afd->audio_format_id = d->afsi.audio_format_id;
        load_chunk_table(&afd->afhi, chunk_table_obj.data);
-       ret = make_status_items(&d);
-       if (ret < 0)
-               goto err;
-       aced.aft_row = aft_row;
-       aced.old_afsi = &d.afsi;
+       aced.aft_row = current_aft_row;
+       aced.old_afsi = &d->afsi;
+       /*
+        * No need to update the status items as the AFSI_CHANGE event will
+        * recreate them.
+        */
        afs_event(AFSI_CHANGE, NULL, &aced);
        ret = save_afd(afd);
 err:
        free(afd->afhi.chunk_table);
        osl_close_disk_object(&chunk_table_obj);
        if (ret < 0) {
-               PARA_ERROR_LOG("%s: %s\n", d.path, para_strerror(-ret));
-               ret = score_delete(aft_row);
+               PARA_ERROR_LOG("%s: %s\n", d->path, para_strerror(-ret));
+               ret = score_delete(current_aft_row);
                if (ret >= 0)
                        goto again;
        }
@@ -2765,9 +2768,27 @@ static int aft_event_handler(enum afs_events event, struct para_buffer *pb,
                if (ret < 0)
                        return ret;
                return audio_file_loop(data, clear_attribute);
-               }
-       default:
+       } case AFSI_CHANGE: {
+               struct afsi_change_event_data *aced = data;
+               uint64_t old_last_played = status_item_ls_data.afsi.last_played;
+               if (aced->aft_row != current_aft_row)
+                       return 0;
+               ret = get_afsi_of_row(aced->aft_row, &status_item_ls_data.afsi);
+               if (ret < 0)
+                       return ret;
+               status_item_ls_data.afsi.last_played = old_last_played;
+               make_status_items();
                return 1;
+       } case AFHI_CHANGE: {
+               if (data != current_aft_row)
+                       return 0;
+               ret = get_afhi_of_row(data, &status_item_ls_data.afhi);
+               if (ret < 0)
+                       return ret;
+               make_status_items();
+               return 1;
+       } default:
+               return 0;
        }
 }