Merge branch 'refs/heads/t/mp'
authorAndre Noll <maan@tuebingen.mpg.de>
Fri, 22 Sep 2017 08:06:45 +0000 (10:06 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Fri, 22 Sep 2017 08:09:08 +0000 (10:09 +0200)
This pile contains the new version 2 mood parser which depends on
flex and bison.

Cooking for a month.

* refs/heads/t/mp:
  Version 2 moods.

28 files changed:
NEWS.md
afh_common.c
afh_recv.c
aft.c
amp_filter.c
audioc.c
audiod.c
audiod_command.c
blob.c
command.c
configure.ac
crypt.c
crypt_backend.h
crypt_common.c
fd.c
filter.c
filter_common.c
gui.c
gui_theme.c
mood.c
ogg_afh.c
ogg_afh_common.c
ogg_afh_common.h
opus_afh.c
para.h
portable_io.h
spx_afh.c
web/manual.md

diff --git a/NEWS.md b/NEWS.md
index d9f092c..b87ae52 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,14 +1,26 @@
 NEWS
 ====
+
 ---------------------
 current master branch
 ---------------------
 
+The highlight of this release is the version 2 mood parser. But there
+is a lot more than that, as summarized in the list below. And of
+course we have many small usability improvements and bug fixes not
+mentioned here.
+
+- A more intuitive syntax for moods ("version 2 moods"). The
+  traditional version 1 moods are still supported but are deprecated
+  now. Removal of the version 1 mood parser is scheduled for the next
+  major release.
+- Flex and bison are now required to build para_server.
 - New sort order for the ls command: -s=h sorts the ls output by hash
   value of the audio file.
 - autogen.sh now runs the test suite after a successful build.
 - The contents of overview.pdf have been integrated into the user
   manual.
+- Fixed sized audio format headers for ogg/opus streams.
 - The doxygen source browser has been disabled temporarily. The
   API reference is still online, though.
 - Overhaul of the source code documentation.
index 1614c27..dd9b319 100644 (file)
@@ -31,7 +31,7 @@ extern afh_init_func mp3_afh_init, ogg_afh_init, aac_afh_init, wma_afh_init,
        spx_afh_init, flac_afh_init, opus_afh_init;
 
 /** The list of all status items */
-const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+const char *status_item_list[] = {STATUS_ITEMS};
 
 /**
  * The list of supported audio formats.
@@ -464,21 +464,21 @@ unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **re
                "%s: %s\n" /* year */
                "%s: %s\n" /* album */
                "%s: %s\n", /* comment */
-               status_item_list[SI_BITRATE], afhi->bitrate,
-               status_item_list[SI_FORMAT], audio_format_name(audio_format_num),
-               status_item_list[SI_FREQUENCY], afhi->frequency,
-               status_item_list[SI_CHANNELS], afhi->channels,
-               status_item_list[SI_SECONDS_TOTAL], afhi->seconds_total,
-               status_item_list[SI_CHUNK_TIME], (long unsigned)afhi->chunk_tv.tv_sec,
+               status_item_list[SI_bitrate], afhi->bitrate,
+               status_item_list[SI_format], audio_format_name(audio_format_num),
+               status_item_list[SI_frequency], afhi->frequency,
+               status_item_list[SI_channels], afhi->channels,
+               status_item_list[SI_seconds_total], afhi->seconds_total,
+               status_item_list[SI_chunk_time], (long unsigned)afhi->chunk_tv.tv_sec,
                        (long unsigned)afhi->chunk_tv.tv_usec,
-               status_item_list[SI_NUM_CHUNKS], afhi->chunks_total,
-               status_item_list[SI_MAX_CHUNK_SIZE], afhi->max_chunk_size,
-               status_item_list[SI_TECHINFO], afhi->techinfo? afhi->techinfo : "",
-               status_item_list[SI_ARTIST], afhi->tags.artist? afhi->tags.artist : "",
-               status_item_list[SI_TITLE], afhi->tags.title? afhi->tags.title : "",
-               status_item_list[SI_YEAR], afhi->tags.year? afhi->tags.year : "",
-               status_item_list[SI_ALBUM], afhi->tags.album? afhi->tags.album : "",
-               status_item_list[SI_COMMENT], afhi->tags.comment? afhi->tags.comment : ""
+               status_item_list[SI_num_chunks], afhi->chunks_total,
+               status_item_list[SI_max_chunk_size], afhi->max_chunk_size,
+               status_item_list[SI_techinfo], afhi->techinfo? afhi->techinfo : "",
+               status_item_list[SI_artist], afhi->tags.artist? afhi->tags.artist : "",
+               status_item_list[SI_title], afhi->tags.title? afhi->tags.title : "",
+               status_item_list[SI_year], afhi->tags.year? afhi->tags.year : "",
+               status_item_list[SI_album], afhi->tags.album? afhi->tags.album : "",
+               status_item_list[SI_comment], afhi->tags.comment? afhi->tags.comment : ""
        );
 }
 
index d2d8b52..36bc988 100644 (file)
@@ -200,7 +200,7 @@ static int afh_recv_post_select(__a_unused struct sched *s, void *context)
                                &pard->afh_context);
                        if (ret < 0)
                                goto out;
-                       PARA_INFO_LOG("adding %zu bytes\n", size);
+                       PARA_DEBUG_LOG("adding %zu bytes\n", size);
                        btr_add_output_dont_free(start, size, btrn);
                }
                ret = -E_RECV_EOF;
diff --git a/aft.c b/aft.c
index 6c07bcc..1679a54 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -756,11 +756,11 @@ static int write_attribute_items(struct para_buffer *b,
        char *att_text;
        int ret;
 
-       WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_BITMAP, "%s\n", att_bitmap);
+       WRITE_STATUS_ITEM(b, SI_attributes_bitmap, "%s\n", att_bitmap);
        ret = get_attribute_text(&afsi->attributes, " ", &att_text);
        if (ret < 0)
                return ret;
-       WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_TXT, "%s\n", att_text);
+       WRITE_STATUS_ITEM(b, SI_attributes_txt, "%s\n", att_text);
        free(att_text);
        return ret;
 }
@@ -769,9 +769,9 @@ static void write_lyrics_items(struct para_buffer *b, struct afs_info *afsi)
 {
        char *lyrics_name;
 
-       WRITE_STATUS_ITEM(b, SI_LYRICS_ID, "%u\n", afsi->lyrics_id);
+       WRITE_STATUS_ITEM(b, SI_lyrics_id, "%u\n", afsi->lyrics_id);
        lyr_get_name_by_id(afsi->lyrics_id, &lyrics_name);
-       WRITE_STATUS_ITEM(b, SI_LYRICS_NAME, "%s\n", lyrics_name?
+       WRITE_STATUS_ITEM(b, SI_lyrics_name, "%s\n", lyrics_name?
                lyrics_name : "(none)");
 }
 
@@ -779,9 +779,9 @@ static void write_image_items(struct para_buffer *b, struct afs_info *afsi)
 {
        char *image_name;
 
-       WRITE_STATUS_ITEM(b, SI_IMAGE_ID, "%u\n", afsi->image_id);
+       WRITE_STATUS_ITEM(b, SI_image_id, "%u\n", afsi->image_id);
        img_get_name_by_id(afsi->image_id, &image_name);
-       WRITE_STATUS_ITEM(b, SI_IMAGE_NAME, "%s\n", image_name?
+       WRITE_STATUS_ITEM(b, SI_image_name, "%s\n", image_name?
                image_name : "(none)");
 }
 
@@ -791,14 +791,14 @@ static void write_filename_items(struct para_buffer *b, const char *path,
        char *val;
 
        if (basename) {
-               WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", path);
+               WRITE_STATUS_ITEM(b, SI_basename, "%s\n", path);
                return;
        }
-       WRITE_STATUS_ITEM(b, SI_PATH, "%s\n", path);
+       WRITE_STATUS_ITEM(b, SI_path, "%s\n", path);
        val = para_basename(path);
-       WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", val? val : "");
+       WRITE_STATUS_ITEM(b, SI_basename, "%s\n", val? val : "");
        val = para_dirname(path);
-       WRITE_STATUS_ITEM(b, SI_DIRECTORY, "%s\n", val? val : "");
+       WRITE_STATUS_ITEM(b, SI_directory, "%s\n", val? val : "");
        free(val);
 }
 
@@ -915,36 +915,36 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
        }
        write_filename_items(b, d->path, lls_opt_given(r_b));
        if (lls_opt_given(r_a))
-               WRITE_STATUS_ITEM(b, SI_SCORE, "%li\n", d->score);
+               WRITE_STATUS_ITEM(b, SI_score, "%li\n", d->score);
        ret = write_attribute_items(b, att_buf, afsi);
        if (ret < 0)
                goto out;
        write_image_items(b, afsi);
        write_lyrics_items(b, afsi);
        hash_to_asc(d->hash, asc_hash);
-       WRITE_STATUS_ITEM(b, SI_HASH, "%s\n", asc_hash);
-       WRITE_STATUS_ITEM(b, SI_BITRATE, "%dkbit/s\n", afhi->bitrate);
-       WRITE_STATUS_ITEM(b, SI_FORMAT, "%s\n",
+       WRITE_STATUS_ITEM(b, SI_hash, "%s\n", asc_hash);
+       WRITE_STATUS_ITEM(b, SI_bitrate, "%dkbit/s\n", afhi->bitrate);
+       WRITE_STATUS_ITEM(b, SI_format, "%s\n",
                audio_format_name(afsi->audio_format_id));
-       WRITE_STATUS_ITEM(b, SI_FREQUENCY, "%dHz\n", afhi->frequency);
-       WRITE_STATUS_ITEM(b, SI_CHANNELS, "%d\n", afhi->channels);
-       WRITE_STATUS_ITEM(b, SI_DURATION, "%s\n", duration_buf);
-       WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
+       WRITE_STATUS_ITEM(b, SI_frequency, "%dHz\n", afhi->frequency);
+       WRITE_STATUS_ITEM(b, SI_channels, "%d\n", afhi->channels);
+       WRITE_STATUS_ITEM(b, SI_duration, "%s\n", duration_buf);
+       WRITE_STATUS_ITEM(b, SI_seconds_total, "%" PRIu32 "\n",
                afhi->seconds_total);
-       WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time);
-       WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%u\n", afsi->num_played);
-       WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp);
-       WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv));
-       WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n",
+       WRITE_STATUS_ITEM(b, SI_last_played, "%s\n", last_played_time);
+       WRITE_STATUS_ITEM(b, SI_num_played, "%u\n", afsi->num_played);
+       WRITE_STATUS_ITEM(b, SI_amplification, "%u\n", afsi->amp);
+       WRITE_STATUS_ITEM(b, SI_chunk_time, "%lu\n", tv2ms(&afhi->chunk_tv));
+       WRITE_STATUS_ITEM(b, SI_num_chunks, "%" PRIu32 "\n",
                afhi->chunks_total);
-       WRITE_STATUS_ITEM(b, SI_MAX_CHUNK_SIZE, "%" PRIu32 "\n",
+       WRITE_STATUS_ITEM(b, SI_max_chunk_size, "%" PRIu32 "\n",
                afhi->max_chunk_size);
-       WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo);
-       WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist);
-       WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title);
-       WRITE_STATUS_ITEM(b, SI_YEAR, "%s\n", afhi->tags.year);
-       WRITE_STATUS_ITEM(b, SI_ALBUM, "%s\n", afhi->tags.album);
-       WRITE_STATUS_ITEM(b, SI_COMMENT, "%s\n", afhi->tags.comment);
+       WRITE_STATUS_ITEM(b, SI_techinfo, "%s\n", afhi->techinfo);
+       WRITE_STATUS_ITEM(b, SI_artist, "%s\n", afhi->tags.artist);
+       WRITE_STATUS_ITEM(b, SI_title, "%s\n", afhi->tags.title);
+       WRITE_STATUS_ITEM(b, SI_year, "%s\n", afhi->tags.year);
+       WRITE_STATUS_ITEM(b, SI_album, "%s\n", afhi->tags.album);
+       WRITE_STATUS_ITEM(b, SI_comment, "%s\n", afhi->tags.comment);
        if (opts->mode == LS_MODE_MBOX) {
                struct osl_object lyrics_def;
                lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def);
@@ -978,8 +978,8 @@ static void make_inode_status_items(struct para_buffer *pb)
        ret = strftime(mtime_str, 29, "%b %d %Y", &mtime_tm);
        assert(ret > 0); /* number of bytes placed in mtime_str */
 out:
-       WRITE_STATUS_ITEM(pb, SI_MTIME, "%s\n", mtime_str);
-       WRITE_STATUS_ITEM(pb, SI_FILE_SIZE, "%ld\n", statbuf.st_size / 1024);
+       WRITE_STATUS_ITEM(pb, SI_mtime, "%s\n", mtime_str);
+       WRITE_STATUS_ITEM(pb, SI_file_size, "%ld\n", statbuf.st_size / 1024);
 }
 
 static int make_status_items(void)
index f3d0d87..4f8e049 100644 (file)
@@ -39,8 +39,8 @@ static void amp_open(struct filter_node *fn)
 
        fn->private_data = pad;
        fn->min_iqs = 2;
-       if (!given && stat_item_values[SI_AMPLIFICATION])
-               sscanf(stat_item_values[SI_AMPLIFICATION], "%u", &pad->amp);
+       if (!given && stat_item_values[SI_amplification])
+               sscanf(stat_item_values[SI_amplification], "%u", &pad->amp);
        else
                pad->amp = amp_arg;
        PARA_INFO_LOG("amplification: %u (scaling factor: %1.2f)\n",
index 1d69b2c..ed39ce6 100644 (file)
--- a/audioc.c
+++ b/audioc.c
@@ -116,7 +116,7 @@ static void version_completer(struct i9e_completion_info *ci,
 static void stat_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *sia[] = {STATUS_ITEM_ARRAY NULL};
+       char *sia[] = {STATUS_ITEMS NULL};
        char *opts[] = {LSG_AUDIOD_CMD_STAT_OPTS, NULL};
 
        if (ci->word_num <= 2 && ci->word && ci->word[0] == '-')
index defd673..42f4c0a 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -666,6 +666,7 @@ static int open_receiver(int format)
                EMBRACE(.name = name, .context = rn));
        ret = r->open(rn);
        if (ret < 0) {
+               PARA_ERROR_LOG("could not open %s receiver\n", name);
                btr_remove_node(&rn->btrn);
                free(rn);
                return ret;
@@ -801,38 +802,38 @@ static int update_item(int itemnum, char *buf)
 {
        long unsigned sec, usec;
 
-       if (stat_task->clock_diff_count && itemnum != SI_CURRENT_TIME)
+       if (stat_task->clock_diff_count && itemnum != SI_current_time)
                return 1;
        free(stat_item_values[itemnum]);
        stat_item_values[itemnum] = para_strdup(buf);
        stat_client_write_item(itemnum);
        switch (itemnum) {
-       case SI_STATUS_FLAGS:
+       case SI_status_flags:
                stat_task->vss_status = 0;
                if (strchr(buf, 'N'))
                        stat_task->vss_status |= VSS_STATUS_FLAG_NEXT;
                if (strchr(buf, 'P'))
                        stat_task->vss_status |= VSS_STATUS_FLAG_PLAYING;
                break;
-       case SI_OFFSET:
+       case SI_offset:
                stat_task->offset_seconds = atoi(buf);
                break;
-       case SI_SECONDS_TOTAL:
+       case SI_seconds_total:
                stat_task->length_seconds = atoi(buf);
                break;
-       case SI_STREAM_START:
+       case SI_stream_start:
                if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) {
                        stat_task->server_stream_start.tv_sec = sec;
                        stat_task->server_stream_start.tv_usec = usec;
                }
                break;
-       case SI_CURRENT_TIME:
+       case SI_current_time:
                if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) {
                        struct timeval tv = {sec, usec};
                        compute_time_diff(&tv);
                }
                break;
-       case SI_FORMAT:
+       case SI_format:
                stat_task->current_audio_format_num
                        = get_audio_format_num(buf);
        }
@@ -1384,10 +1385,10 @@ static int status_post_select(struct sched *s, void *context)
                client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s);
                set_stat_task_restart_barrier(5);
        }
-       free(stat_item_values[SI_BASENAME]);
-       stat_item_values[SI_BASENAME] = para_strdup(
+       free(stat_item_values[SI_basename]);
+       stat_item_values[SI_basename] = para_strdup(
                "no connection to para_server");
-       stat_client_write_item(SI_BASENAME);
+       stat_client_write_item(SI_basename);
        st->last_status_read = *now;
 out:
        start_stop_decoders();
index cccc2a8..a6a49b7 100644 (file)
@@ -82,7 +82,7 @@ static INITIALIZED_LIST_HEAD(client_list);
 static int num_clients;
 
 /** The list of all status items used by para_{server,audiod,gui}. */
-const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+const char *status_item_list[] = {STATUS_ITEMS};
 
 static void dump_stat_client_list(void)
 {
@@ -481,41 +481,41 @@ void audiod_status_dump(bool force)
 {
        char *old, *new;
 
-       old = stat_item_values[SI_PLAY_TIME];
+       old = stat_item_values[SI_play_time];
        new = get_time_string();
        if (new) {
                if (force || !old || strcmp(old, new)) {
                        free(old);
-                       stat_item_values[SI_PLAY_TIME] = new;
-                       stat_client_write_item(SI_PLAY_TIME);
+                       stat_item_values[SI_play_time] = new;
+                       stat_client_write_item(SI_play_time);
                } else
                        free(new);
        }
 
        new = daemon_get_uptime_str(now);
-       old = stat_item_values[SI_AUDIOD_UPTIME];
+       old = stat_item_values[SI_audiod_uptime];
        if (force || !old || strcmp(old, new)) {
                free(old);
-               stat_item_values[SI_AUDIOD_UPTIME] = new;
-               stat_client_write_item(SI_AUDIOD_UPTIME);
+               stat_item_values[SI_audiod_uptime] = new;
+               stat_client_write_item(SI_audiod_uptime);
        } else
                free(new);
 
-       old = stat_item_values[SI_AUDIOD_STATUS];
+       old = stat_item_values[SI_audiod_status];
        new = audiod_status_string();
        if (force || !old || strcmp(old, new)) {
                free(old);
-               stat_item_values[SI_AUDIOD_STATUS] = new;
-               stat_client_write_item(SI_AUDIOD_STATUS);
+               stat_item_values[SI_audiod_status] = new;
+               stat_client_write_item(SI_audiod_status);
        } else
                free(new);
 
-       old = stat_item_values[SI_DECODER_FLAGS];
+       old = stat_item_values[SI_decoder_flags];
        new = audiod_get_decoder_flags();
        if (force || !old || strcmp(old, new)) {
                free(old);
-               stat_item_values[SI_DECODER_FLAGS] = new;
-               stat_client_write_item(SI_DECODER_FLAGS);
+               stat_item_values[SI_decoder_flags] = new;
+               stat_client_write_item(SI_decoder_flags);
        } else
                free(new);
 }
diff --git a/blob.c b/blob.c
index 2d7c605..7798a49 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -33,8 +33,8 @@
  */
 static int uint32_compare(const struct osl_object *obj1, const struct osl_object *obj2)
 {
-       uint32_t d1 = read_u32((const char *)obj1->data);
-       uint32_t d2 = read_u32((const char *)obj2->data);
+       uint32_t d1 = read_u32(obj1->data);
+       uint32_t d2 = read_u32(obj2->data);
 
        if (d1 < d2)
                return 1;
index 077c159..6956433 100644 (file)
--- a/command.c
+++ b/command.c
@@ -111,14 +111,14 @@ static unsigned get_status(struct misc_meta_data *nmmd, bool parser_friendly,
         * clang is not smart enough to prove this and complains nevertheless.
         * Casting the return value to void silences clang.
         */
-       (void)WRITE_STATUS_ITEM(&b, SI_STATUS, "%s\n", status);
-       (void)WRITE_STATUS_ITEM(&b, SI_STATUS_FLAGS, "%s\n", flags);
-       (void)WRITE_STATUS_ITEM(&b, SI_OFFSET, "%li\n", offset);
-       (void)WRITE_STATUS_ITEM(&b, SI_AFS_MODE, "%s\n", mmd->afs_mode_string);
-       (void)WRITE_STATUS_ITEM(&b, SI_STREAM_START, "%lu.%lu\n",
+       (void)WRITE_STATUS_ITEM(&b, SI_status, "%s\n", status);
+       (void)WRITE_STATUS_ITEM(&b, SI_status_flags, "%s\n", flags);
+       (void)WRITE_STATUS_ITEM(&b, SI_offset, "%li\n", offset);
+       (void)WRITE_STATUS_ITEM(&b, SI_afs_mode, "%s\n", mmd->afs_mode_string);
+       (void)WRITE_STATUS_ITEM(&b, SI_stream_start, "%lu.%lu\n",
                (long unsigned)nmmd->stream_start.tv_sec,
                (long unsigned)nmmd->stream_start.tv_usec);
-       (void)WRITE_STATUS_ITEM(&b, SI_CURRENT_TIME, "%lu.%lu\n",
+       (void)WRITE_STATUS_ITEM(&b, SI_current_time, "%lu.%lu\n",
                (long unsigned)current_time.tv_sec,
                (long unsigned)current_time.tv_usec);
        free(flags);
@@ -426,36 +426,36 @@ EXPORT_SERVER_CMD_HANDLER(version);
 
 /** These status items are cleared if no audio file is currently open. */
 #define EMPTY_STATUS_ITEMS \
-       ITEM(PATH) \
-       ITEM(DIRECTORY) \
-       ITEM(BASENAME) \
-       ITEM(SCORE) \
-       ITEM(ATTRIBUTES_BITMAP) \
-       ITEM(ATTRIBUTES_TXT) \
-       ITEM(HASH) \
-       ITEM(IMAGE_ID) \
-       ITEM(IMAGE_NAME) \
-       ITEM(LYRICS_ID) \
-       ITEM(LYRICS_NAME) \
-       ITEM(BITRATE) \
-       ITEM(FORMAT) \
-       ITEM(FREQUENCY) \
-       ITEM(CHANNELS) \
-       ITEM(DURATION) \
-       ITEM(SECONDS_TOTAL) \
-       ITEM(NUM_PLAYED) \
-       ITEM(LAST_PLAYED) \
-       ITEM(TECHINFO) \
-       ITEM(ARTIST) \
-       ITEM(TITLE) \
-       ITEM(YEAR) \
-       ITEM(ALBUM) \
-       ITEM(COMMENT) \
-       ITEM(MTIME) \
-       ITEM(FILE_SIZE) \
-       ITEM(CHUNK_TIME) \
-       ITEM(NUM_CHUNKS) \
-       ITEM(AMPLIFICATION) \
+       ITEM(path) \
+       ITEM(directory) \
+       ITEM(basename) \
+       ITEM(score) \
+       ITEM(attributes_bitmap) \
+       ITEM(attributes_txt) \
+       ITEM(hash) \
+       ITEM(image_id) \
+       ITEM(image_name) \
+       ITEM(lyrics_id) \
+       ITEM(lyrics_name) \
+       ITEM(bitrate) \
+       ITEM(format) \
+       ITEM(frequency) \
+       ITEM(channels) \
+       ITEM(duration) \
+       ITEM(seconds_total) \
+       ITEM(num_played) \
+       ITEM(last_played) \
+       ITEM(techinfo) \
+       ITEM(artist) \
+       ITEM(title) \
+       ITEM(year) \
+       ITEM(album) \
+       ITEM(comment) \
+       ITEM(mtime) \
+       ITEM(file_size) \
+       ITEM(chunk_time) \
+       ITEM(num_chunks) \
+       ITEM(amplification) \
 
 /*
  * Create a set of audio-file related status items with empty values. These are
index bf55bd3..1a375e9 100644 (file)
@@ -806,33 +806,9 @@ if test $HAVE_READLINE = yes; then
 fi
 audioc_objs="$audioc_errlist_objs"
 AC_SUBST(audioc_objs, add_dot_o($audioc_objs))
-################################################################## status items
-
-status_items="basename status num_played mtime bitrate frequency file_size
-status_flags format score techinfo afs_mode
-attributes_txt decoder_flags audiod_status play_time attributes_bitmap
-offset seconds_total stream_start current_time audiod_uptime image_id
-lyrics_id duration directory lyrics_name image_name path hash channels
-last_played num_chunks chunk_time amplification artist title year album
-comment max_chunk_size"
-
-result=
-for i in $status_items; do
-       result="$result SI_$(echo $i | tr 'a-z' 'A-Z'), "
-done
-AC_DEFINE_UNQUOTED(STATUS_ITEM_ENUM, [$result],
-       [enum of all status items])
-
-result=
-for i in $status_items; do
-       result="$result \"$i\", "
-done
-AC_DEFINE_UNQUOTED(STATUS_ITEM_ARRAY, [$result],
-       [char * array of all status items])
 
 AC_DEFINE_UNQUOTED(AUDIO_FORMAT_HANDLERS, "$audio_format_handlers",
        [formats supported by para_server and para_afh])
-
 AC_SUBST(executables)
 
 AC_OUTPUT
diff --git a/crypt.c b/crypt.c
index f1e42d4..d4ffdf8 100644 (file)
--- a/crypt.c
+++ b/crypt.c
@@ -23,6 +23,7 @@
 #include "fd.h"
 #include "crypt_backend.h"
 #include "base64.h"
+#include "portable_io.h"
 
 struct asymmetric_key {
        RSA *rsa;
@@ -96,7 +97,7 @@ static int read_bignum(const unsigned char *buf, size_t len, BIGNUM **result)
                return -E_BIGNUM;
        if (p + 4 > end)
                return -E_BIGNUM;
-       bnsize = read_ssh_u32(p);
+       bnsize = read_u32_be(p);
        PARA_DEBUG_LOG("bnsize: %u\n", bnsize);
        p += 4;
        if (p + bnsize < p)
index fccdd2e..8500897 100644 (file)
@@ -12,6 +12,5 @@
 #define AES_CRT128_BLOCK_SIZE 16
 
 size_t is_ssh_rsa_key(char *data, size_t size);
-uint32_t read_ssh_u32(const void *vp);
 int check_ssh_key_header(const unsigned char *blob, int blen);
 int check_private_key_file(const char *file);
index 1fd8189..ac8564e 100644 (file)
@@ -13,6 +13,7 @@
 #include "string.h"
 #include "crypt.h"
 #include "crypt_backend.h"
+#include "portable_io.h"
 
 /** If the key begins with this text, we treat it as an ssh key. */
 #define KEY_TYPE_TXT "ssh-rsa"
@@ -45,29 +46,6 @@ size_t is_ssh_rsa_key(char *data, size_t size)
        return cp - data;
 }
 
-/**
- * Read a 4-byte number from a buffer in big-endian format.
- *
- * \param vp The buffer.
- *
- * The byte-order of the buffer is expected to be big-endian, unlike read_u32()
- * of portable_io.h which expects little endian.
- *
- * \return The 32 bit number given by \a vp.
- */
-uint32_t read_ssh_u32(const void *vp)
-{
-       const unsigned char *p = (const unsigned char *)vp;
-       uint32_t v;
-
-       v  = (uint32_t)p[0] << 24;
-       v |= (uint32_t)p[1] << 16;
-       v |= (uint32_t)p[2] << 8;
-       v |= (uint32_t)p[3];
-
-       return v;
-}
-
 /**
  * Sanity checks for the header of an ssh key.
  *
@@ -88,7 +66,7 @@ int check_ssh_key_header(const unsigned char *blob, int blen)
 
        if (p + 4 > end)
                return -E_SSH_KEY_HEADER;
-       rlen = read_ssh_u32(p);
+       rlen = read_u32_be(p);
        p += 4;
        if (p + rlen < p)
                return -E_SSH_KEY_HEADER;
diff --git a/fd.c b/fd.c
index dc4fd59..4973644 100644 (file)
--- a/fd.c
+++ b/fd.c
@@ -573,20 +573,6 @@ close_cwd:
        return ret;
 }
 
-/**
- * A wrapper for fchdir().
- *
- * \param fd An open file descriptor.
- *
- * \return Standard.
- */
-static int para_fchdir(int fd)
-{
-       if (fchdir(fd) < 0)
-               return -ERRNO_TO_PARA_ERROR(errno);
-       return 1;
-}
-
 /**
  * A wrapper for mkdir(2).
  *
@@ -749,7 +735,7 @@ int for_each_file_in_dir(const char *dirname,
 {
        DIR *dir;
        struct dirent *entry;
-       int cwd_fd, ret2, ret = para_opendir(dirname, &dir, &cwd_fd);
+       int cwd_fd, ret = para_opendir(dirname, &dir, &cwd_fd);
 
        if (ret < 0)
                return ret == -ERRNO_TO_PARA_ERROR(EACCES)? 1 : ret;
@@ -785,9 +771,8 @@ int for_each_file_in_dir(const char *dirname,
        ret = 1;
 out:
        closedir(dir);
-       ret2 = para_fchdir(cwd_fd);
-       if (ret2 < 0 && ret >= 0)
-               ret = ret2;
+       if (fchdir(cwd_fd) < 0 && ret >= 0)
+               ret = -ERRNO_TO_PARA_ERROR(errno);
        close(cwd_fd);
        return ret;
 }
index d5dac67..156e049 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -34,7 +34,7 @@ static struct lls_parse_result *lpr; /* command line options */
 #define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name)))
 
 /** The list of all status items used by para_{server,audiod,gui}. */
-const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+const char *status_item_list[] = {STATUS_ITEMS};
 
 /**
  * Dummy version which only contains NULL pointers.
index b406951..5533d4d 100644 (file)
@@ -21,7 +21,7 @@
 #include "string.h"
 
 /** Iterate over all filters. */
-#define FOR_EACH_FILTER(j) for (j = 1; lls_cmd(j, filter_cmd_suite); j++)
+#define FOR_EACH_FILTER(j) for (j = 1; FILTER_CMD(j); j++)
 
 /**
  * Obtain a reference to a filter structure.
diff --git a/gui.c b/gui.c
index 5bad7e1..493bc3c 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -569,19 +569,19 @@ static int update_item(int item_num, char *buf)
        if (buf && buf[0])
                goto dup;
        switch (item_num) {
-       case SI_ARTIST:
+       case SI_artist:
                *c = para_strdup("(artist tag not set)");
                goto print;
-       case SI_TITLE:
+       case SI_title:
                *c = para_strdup("(title tag not set)");
                goto print;
-       case SI_YEAR:
+       case SI_year:
                *c = para_strdup("????");
                goto print;
-       case SI_ALBUM:
+       case SI_album:
                *c = para_strdup("(album tag not set)");
                goto print;
-       case SI_COMMENT:
+       case SI_comment:
                *c = para_strdup("(comment tag not set)");
                goto print;
        }
@@ -680,8 +680,8 @@ static int status_post_select(struct sched *s, void *context)
                close(st->fd);
                st->fd = -1;
                clear_all_items();
-               free(stat_content[SI_BASENAME]);
-               stat_content[SI_BASENAME] =
+               free(stat_content[SI_basename]);
+               stat_content[SI_basename] =
                        para_strdup("stat command terminated!?");
                print_all_items();
                return 0;
index fb8f2f9..78527ef 100644 (file)
@@ -34,32 +34,32 @@ static void init_theme_simple(struct gui_theme *t)
        t->dflt.bg = COLOR_BLUE;
        t->sep_char = '*';
 
-       d[SI_BASENAME].prefix = "";
-       d[SI_BASENAME].postfix = "";
-       d[SI_BASENAME].color.fg = COLOR_WHITE;
-       d[SI_BASENAME].color.bg = COLOR_BLUE;
-       d[SI_BASENAME].align = CENTER;
-       d[SI_BASENAME].x = 0;
-       d[SI_BASENAME].y = 7;
-       d[SI_BASENAME].len = 100;
-
-       d[SI_STATUS].prefix = "para_server: ";
-       d[SI_STATUS].postfix = "";
-       d[SI_STATUS].color.fg = COLOR_WHITE;
-       d[SI_STATUS].color.bg = COLOR_BLUE;
-       d[SI_STATUS].align = CENTER;
-       d[SI_STATUS].x = 0;
-       d[SI_STATUS].y = 60;
-       d[SI_STATUS].len = 50;
-
-       d[SI_AUDIOD_STATUS].prefix = "para_audiod: ";
-       d[SI_AUDIOD_STATUS].postfix = "";
-       d[SI_AUDIOD_STATUS].color.fg = COLOR_WHITE;
-       d[SI_AUDIOD_STATUS].color.bg = COLOR_BLUE;
-       d[SI_AUDIOD_STATUS].align = CENTER;
-       d[SI_AUDIOD_STATUS].x = 50;
-       d[SI_AUDIOD_STATUS].y = 60;
-       d[SI_AUDIOD_STATUS].len = 50;
+       d[SI_basename].prefix = "";
+       d[SI_basename].postfix = "";
+       d[SI_basename].color.fg = COLOR_WHITE;
+       d[SI_basename].color.bg = COLOR_BLUE;
+       d[SI_basename].align = CENTER;
+       d[SI_basename].x = 0;
+       d[SI_basename].y = 7;
+       d[SI_basename].len = 100;
+
+       d[SI_status].prefix = "para_server: ";
+       d[SI_status].postfix = "";
+       d[SI_status].color.fg = COLOR_WHITE;
+       d[SI_status].color.bg = COLOR_BLUE;
+       d[SI_status].align = CENTER;
+       d[SI_status].x = 0;
+       d[SI_status].y = 60;
+       d[SI_status].len = 50;
+
+       d[SI_audiod_status].prefix = "para_audiod: ";
+       d[SI_audiod_status].postfix = "";
+       d[SI_audiod_status].color.fg = COLOR_WHITE;
+       d[SI_audiod_status].color.bg = COLOR_BLUE;
+       d[SI_audiod_status].align = CENTER;
+       d[SI_audiod_status].x = 50;
+       d[SI_audiod_status].y = 60;
+       d[SI_audiod_status].len = 50;
 
 }
 
@@ -92,266 +92,266 @@ static void init_theme_colorful_blackness(struct gui_theme *t)
        t->dflt.fg = COLOR_MAGENTA;
 
 
-       d[SI_PLAY_TIME].prefix = "";
-       d[SI_PLAY_TIME].postfix = "";
-       d[SI_PLAY_TIME].color.fg = COLOR_CYAN;
-       d[SI_PLAY_TIME].color.bg = COLOR_BLACK;
-       d[SI_PLAY_TIME].align = CENTER;
-       d[SI_PLAY_TIME].x = 0;
-       d[SI_PLAY_TIME].y = 7;
-       d[SI_PLAY_TIME].len = 35;
-
-       d[SI_BASENAME].prefix = "";
-       d[SI_BASENAME].postfix = "";
-       d[SI_BASENAME].color.fg = COLOR_CYAN;
-       d[SI_BASENAME].color.bg = COLOR_BLACK;
-       d[SI_BASENAME].align = LEFT;
-       d[SI_BASENAME].x = 35;
-       d[SI_BASENAME].y = 7;
-       d[SI_BASENAME].len = 65;
-
-       d[SI_STATUS].prefix = "";
-       d[SI_STATUS].postfix = " ";
-       d[SI_STATUS].color.fg = COLOR_RED;
-       d[SI_STATUS].color.bg = COLOR_BLACK;
-       d[SI_STATUS].align = RIGHT;
-       d[SI_STATUS].x = 0;
-       d[SI_STATUS].y = 17;
-       d[SI_STATUS].len = 11;
-
-       d[SI_STATUS_FLAGS].prefix = "(";
-       d[SI_STATUS_FLAGS].postfix = ")";
-       d[SI_STATUS_FLAGS].color.fg = COLOR_RED;
-       d[SI_STATUS_FLAGS].color.bg = COLOR_BLACK;
-       d[SI_STATUS_FLAGS].align = LEFT;
-       d[SI_STATUS_FLAGS].x = 11;
-       d[SI_STATUS_FLAGS].y = 17;
-       d[SI_STATUS_FLAGS].len = 10;
-
-       d[SI_IMAGE_ID].prefix = "img: ";
-       d[SI_IMAGE_ID].postfix = "";
-       d[SI_IMAGE_ID].color.fg = COLOR_RED;
-       d[SI_IMAGE_ID].color.bg = COLOR_BLACK;
-       d[SI_IMAGE_ID].align = CENTER;
-       d[SI_IMAGE_ID].x = 21;
-       d[SI_IMAGE_ID].y = 17;
-       d[SI_IMAGE_ID].len = 10;
-
-       d[SI_LYRICS_ID].prefix = "lyr: ";
-       d[SI_LYRICS_ID].postfix = "";
-       d[SI_LYRICS_ID].color.fg = COLOR_RED;
-       d[SI_LYRICS_ID].color.bg = COLOR_BLACK;
-       d[SI_LYRICS_ID].align = CENTER;
-       d[SI_LYRICS_ID].x = 31;
-       d[SI_LYRICS_ID].y = 17;
-       d[SI_LYRICS_ID].len = 11;
-
-       d[SI_FORMAT].prefix = "format: ";
-       d[SI_FORMAT].postfix = "";
-       d[SI_FORMAT].color.fg = COLOR_RED;
-       d[SI_FORMAT].color.bg = COLOR_BLACK;
-       d[SI_FORMAT].align = CENTER;
-       d[SI_FORMAT].x = 42;
-       d[SI_FORMAT].y = 17;
-       d[SI_FORMAT].len = 18;
-
-       d[SI_NUM_PLAYED].prefix = "#";
-       d[SI_NUM_PLAYED].postfix = "";
-       d[SI_NUM_PLAYED].color.fg = COLOR_RED;
-       d[SI_NUM_PLAYED].color.bg = COLOR_BLACK;
-       d[SI_NUM_PLAYED].align = LEFT;
-       d[SI_NUM_PLAYED].x = 60;
-       d[SI_NUM_PLAYED].y = 17;
-       d[SI_NUM_PLAYED].len = 5;
-
-       d[SI_BITRATE].prefix = "";
-       d[SI_BITRATE].postfix = "";
-       d[SI_BITRATE].color.fg = COLOR_RED;
-       d[SI_BITRATE].color.bg = COLOR_BLACK;
-       d[SI_BITRATE].align = CENTER;
-       d[SI_BITRATE].x = 65;
-       d[SI_BITRATE].y = 17;
-       d[SI_BITRATE].len = 13;
-
-       d[SI_FREQUENCY].prefix = "";
-       d[SI_FREQUENCY].postfix = "";
-       d[SI_FREQUENCY].color.fg = COLOR_RED;
-       d[SI_FREQUENCY].color.bg = COLOR_BLACK;
-       d[SI_FREQUENCY].align = CENTER;
-       d[SI_FREQUENCY].x = 78;
-       d[SI_FREQUENCY].y = 17;
-       d[SI_FREQUENCY].len = 10;
-
-       d[SI_SCORE].prefix = "sc: ";
-       d[SI_SCORE].postfix = "";
-       d[SI_SCORE].color.fg = COLOR_RED;
-       d[SI_SCORE].color.bg = COLOR_BLACK;
-       d[SI_SCORE].align = CENTER;
-       d[SI_SCORE].x = 88;
-       d[SI_SCORE].y = 17;
-       d[SI_SCORE].len = 10;
-
-       d[SI_AUDIOD_STATUS].prefix = "";
-       d[SI_AUDIOD_STATUS].postfix = "";
-       d[SI_AUDIOD_STATUS].color.fg = COLOR_MAGENTA;
-       d[SI_AUDIOD_STATUS].color.bg = COLOR_BLACK;
-       d[SI_AUDIOD_STATUS].align = CENTER;
-       d[SI_AUDIOD_STATUS].x = 0;
-       d[SI_AUDIOD_STATUS].y = 27;
-       d[SI_AUDIOD_STATUS].len = 5;
-
-       d[SI_DECODER_FLAGS].prefix = "[";
-       d[SI_DECODER_FLAGS].postfix = "]";
-       d[SI_DECODER_FLAGS].color.fg = COLOR_MAGENTA;
-       d[SI_DECODER_FLAGS].color.bg = COLOR_BLACK;
-       d[SI_DECODER_FLAGS].align = CENTER;
-       d[SI_DECODER_FLAGS].x = 5;
-       d[SI_DECODER_FLAGS].y = 27;
-       d[SI_DECODER_FLAGS].len = 10;
-
-       d[SI_MTIME].prefix = "mod: ";
-       d[SI_MTIME].postfix = "";
-       d[SI_MTIME].color.fg = COLOR_MAGENTA;
-       d[SI_MTIME].color.bg = COLOR_BLACK;
-       d[SI_MTIME].align = CENTER;
-       d[SI_MTIME].x = 15;
-       d[SI_MTIME].y = 27;
-       d[SI_MTIME].len = 22;
-
-       d[SI_FILE_SIZE].prefix = "";
-       d[SI_FILE_SIZE].postfix = "kb";
-       d[SI_FILE_SIZE].color.fg = COLOR_MAGENTA;
-       d[SI_FILE_SIZE].color.bg = COLOR_BLACK;
-       d[SI_FILE_SIZE].align = CENTER;
-       d[SI_FILE_SIZE].x = 37;
-       d[SI_FILE_SIZE].y = 27;
-       d[SI_FILE_SIZE].len = 10;
-
-       d[SI_CHANNELS].prefix = "";
-       d[SI_CHANNELS].postfix = "ch";
-       d[SI_CHANNELS].color.fg = COLOR_MAGENTA;
-       d[SI_CHANNELS].color.bg = COLOR_BLACK;
-       d[SI_CHANNELS].align = CENTER;
-       d[SI_CHANNELS].x = 47;
-       d[SI_CHANNELS].y = 27;
-       d[SI_CHANNELS].len = 5;
-
-       d[SI_LAST_PLAYED].prefix = "lp: ";
-       d[SI_LAST_PLAYED].postfix = "";
-       d[SI_LAST_PLAYED].color.fg = COLOR_MAGENTA;
-       d[SI_LAST_PLAYED].color.bg = COLOR_BLACK;
-       d[SI_LAST_PLAYED].align = CENTER;
-       d[SI_LAST_PLAYED].x = 52;
-       d[SI_LAST_PLAYED].y = 27;
-       d[SI_LAST_PLAYED].len = 21;
-
-       d[SI_NUM_CHUNKS].prefix = "";
-       d[SI_NUM_CHUNKS].postfix = "x";
-       d[SI_NUM_CHUNKS].color.fg = COLOR_MAGENTA;
-       d[SI_NUM_CHUNKS].color.bg = COLOR_BLACK;
-       d[SI_NUM_CHUNKS].align = RIGHT;
-       d[SI_NUM_CHUNKS].x = 73;
-       d[SI_NUM_CHUNKS].y = 27;
-       d[SI_NUM_CHUNKS].len = 11;
-
-       d[SI_CHUNK_TIME].prefix = "";
-       d[SI_CHUNK_TIME].postfix = "ms";
-       d[SI_CHUNK_TIME].color.fg = COLOR_MAGENTA;
-       d[SI_CHUNK_TIME].color.bg = COLOR_BLACK;
-       d[SI_CHUNK_TIME].align = LEFT;
-       d[SI_CHUNK_TIME].x = 84;
-       d[SI_CHUNK_TIME].y = 27;
-       d[SI_CHUNK_TIME].len = 8;
-
-       d[SI_AMPLIFICATION].prefix = "amp:";
-       d[SI_AMPLIFICATION].postfix = "";
-       d[SI_AMPLIFICATION].color.fg = COLOR_MAGENTA;
-       d[SI_AMPLIFICATION].color.bg = COLOR_BLACK;
-       d[SI_AMPLIFICATION].align = RIGHT;
-       d[SI_AMPLIFICATION].x = 92;
-       d[SI_AMPLIFICATION].y = 27;
-       d[SI_AMPLIFICATION].len = 8;
-
-       d[SI_TECHINFO].prefix = "";
-       d[SI_TECHINFO].postfix = "";
-       d[SI_TECHINFO].color.fg = COLOR_GREEN;
-       d[SI_TECHINFO].color.bg = COLOR_BLACK;
-       d[SI_TECHINFO].align = CENTER;
-       d[SI_TECHINFO].x = 0;
-       d[SI_TECHINFO].y = 43;
-       d[SI_TECHINFO].len = 100;
-
-       d[SI_TITLE].prefix = "";
-       d[SI_TITLE].postfix = ",";
-       d[SI_TITLE].color.fg = COLOR_GREEN;
-       d[SI_TITLE].color.bg = COLOR_BLACK;
-       d[SI_TITLE].align = RIGHT;
-       d[SI_TITLE].x = 0;
-       d[SI_TITLE].y = 53;
-       d[SI_TITLE].len = 45;
-
-       d[SI_ARTIST].prefix = " by ";
-       d[SI_ARTIST].postfix = "";
-       d[SI_ARTIST].color.fg = COLOR_GREEN;
-       d[SI_ARTIST].color.bg = COLOR_BLACK;
-       d[SI_ARTIST].align = LEFT;
-       d[SI_ARTIST].x = 45;
-       d[SI_ARTIST].y = 53;
-       d[SI_ARTIST].len = 45;
-
-       d[SI_YEAR].prefix = "(";
-       d[SI_YEAR].postfix = ")";
-       d[SI_YEAR].color.fg = COLOR_GREEN;
-       d[SI_YEAR].color.bg = COLOR_BLACK;
-       d[SI_YEAR].align = RIGHT;
-       d[SI_YEAR].x = 90;
-       d[SI_YEAR].y = 53;
-       d[SI_YEAR].len = 10;
-
-       d[SI_ALBUM].prefix = "A: ";
-       d[SI_ALBUM].postfix = ",";
-       d[SI_ALBUM].color.fg = COLOR_GREEN;
-       d[SI_ALBUM].color.bg = COLOR_BLACK;
-       d[SI_ALBUM].align = RIGHT;
-       d[SI_ALBUM].x = 0;
-       d[SI_ALBUM].y = 63;
-       d[SI_ALBUM].len = 50;
-
-       d[SI_COMMENT].prefix = " C: ";
-       d[SI_COMMENT].postfix = "";
-       d[SI_COMMENT].color.fg = COLOR_GREEN;
-       d[SI_COMMENT].color.bg = COLOR_BLACK;
-       d[SI_COMMENT].align = LEFT;
-       d[SI_COMMENT].x = 50;
-       d[SI_COMMENT].y = 63;
-       d[SI_COMMENT].len = 50;
-
-       d[SI_AFS_MODE].prefix = "";
-       d[SI_AFS_MODE].postfix = "";
-       d[SI_AFS_MODE].color.fg = COLOR_YELLOW;
-       d[SI_AFS_MODE].color.bg = COLOR_BLACK;
-       d[SI_AFS_MODE].align = CENTER;
-       d[SI_AFS_MODE].x = 0;
-       d[SI_AFS_MODE].y = 77;
-       d[SI_AFS_MODE].len = 100;
-
-       d[SI_ATTRIBUTES_TXT].prefix = "";
-       d[SI_ATTRIBUTES_TXT].postfix = "";
-       d[SI_ATTRIBUTES_TXT].color.fg = COLOR_YELLOW;
-       d[SI_ATTRIBUTES_TXT].color.bg = COLOR_BLACK;
-       d[SI_ATTRIBUTES_TXT].align = CENTER;
-       d[SI_ATTRIBUTES_TXT].x = 0;
-       d[SI_ATTRIBUTES_TXT].y = 87;
-       d[SI_ATTRIBUTES_TXT].len = 100;
-
-       d[SI_DIRECTORY].prefix = "dir: ";
-       d[SI_DIRECTORY].postfix = "";
-       d[SI_DIRECTORY].color.fg = COLOR_YELLOW;
-       d[SI_DIRECTORY].color.bg = COLOR_BLACK;
-       d[SI_DIRECTORY].align = CENTER;
-       d[SI_DIRECTORY].x = 0;
-       d[SI_DIRECTORY].y = 97;
-       d[SI_DIRECTORY].len = 100;
+       d[SI_play_time].prefix = "";
+       d[SI_play_time].postfix = "";
+       d[SI_play_time].color.fg = COLOR_CYAN;
+       d[SI_play_time].color.bg = COLOR_BLACK;
+       d[SI_play_time].align = CENTER;
+       d[SI_play_time].x = 0;
+       d[SI_play_time].y = 7;
+       d[SI_play_time].len = 35;
+
+       d[SI_basename].prefix = "";
+       d[SI_basename].postfix = "";
+       d[SI_basename].color.fg = COLOR_CYAN;
+       d[SI_basename].color.bg = COLOR_BLACK;
+       d[SI_basename].align = LEFT;
+       d[SI_basename].x = 35;
+       d[SI_basename].y = 7;
+       d[SI_basename].len = 65;
+
+       d[SI_status].prefix = "";
+       d[SI_status].postfix = " ";
+       d[SI_status].color.fg = COLOR_RED;
+       d[SI_status].color.bg = COLOR_BLACK;
+       d[SI_status].align = RIGHT;
+       d[SI_status].x = 0;
+       d[SI_status].y = 17;
+       d[SI_status].len = 11;
+
+       d[SI_status_flags].prefix = "(";
+       d[SI_status_flags].postfix = ")";
+       d[SI_status_flags].color.fg = COLOR_RED;
+       d[SI_status_flags].color.bg = COLOR_BLACK;
+       d[SI_status_flags].align = LEFT;
+       d[SI_status_flags].x = 11;
+       d[SI_status_flags].y = 17;
+       d[SI_status_flags].len = 10;
+
+       d[SI_image_id].prefix = "img: ";
+       d[SI_image_id].postfix = "";
+       d[SI_image_id].color.fg = COLOR_RED;
+       d[SI_image_id].color.bg = COLOR_BLACK;
+       d[SI_image_id].align = CENTER;
+       d[SI_image_id].x = 21;
+       d[SI_image_id].y = 17;
+       d[SI_image_id].len = 10;
+
+       d[SI_lyrics_id].prefix = "lyr: ";
+       d[SI_lyrics_id].postfix = "";
+       d[SI_lyrics_id].color.fg = COLOR_RED;
+       d[SI_lyrics_id].color.bg = COLOR_BLACK;
+       d[SI_lyrics_id].align = CENTER;
+       d[SI_lyrics_id].x = 31;
+       d[SI_lyrics_id].y = 17;
+       d[SI_lyrics_id].len = 11;
+
+       d[SI_format].prefix = "format: ";
+       d[SI_format].postfix = "";
+       d[SI_format].color.fg = COLOR_RED;
+       d[SI_format].color.bg = COLOR_BLACK;
+       d[SI_format].align = CENTER;
+       d[SI_format].x = 42;
+       d[SI_format].y = 17;
+       d[SI_format].len = 18;
+
+       d[SI_num_played].prefix = "#";
+       d[SI_num_played].postfix = "";
+       d[SI_num_played].color.fg = COLOR_RED;
+       d[SI_num_played].color.bg = COLOR_BLACK;
+       d[SI_num_played].align = LEFT;
+       d[SI_num_played].x = 60;
+       d[SI_num_played].y = 17;
+       d[SI_num_played].len = 5;
+
+       d[SI_bitrate].prefix = "";
+       d[SI_bitrate].postfix = "";
+       d[SI_bitrate].color.fg = COLOR_RED;
+       d[SI_bitrate].color.bg = COLOR_BLACK;
+       d[SI_bitrate].align = CENTER;
+       d[SI_bitrate].x = 65;
+       d[SI_bitrate].y = 17;
+       d[SI_bitrate].len = 13;
+
+       d[SI_frequency].prefix = "";
+       d[SI_frequency].postfix = "";
+       d[SI_frequency].color.fg = COLOR_RED;
+       d[SI_frequency].color.bg = COLOR_BLACK;
+       d[SI_frequency].align = CENTER;
+       d[SI_frequency].x = 78;
+       d[SI_frequency].y = 17;
+       d[SI_frequency].len = 10;
+
+       d[SI_score].prefix = "sc: ";
+       d[SI_score].postfix = "";
+       d[SI_score].color.fg = COLOR_RED;
+       d[SI_score].color.bg = COLOR_BLACK;
+       d[SI_score].align = CENTER;
+       d[SI_score].x = 88;
+       d[SI_score].y = 17;
+       d[SI_score].len = 10;
+
+       d[SI_audiod_status].prefix = "";
+       d[SI_audiod_status].postfix = "";
+       d[SI_audiod_status].color.fg = COLOR_MAGENTA;
+       d[SI_audiod_status].color.bg = COLOR_BLACK;
+       d[SI_audiod_status].align = CENTER;
+       d[SI_audiod_status].x = 0;
+       d[SI_audiod_status].y = 27;
+       d[SI_audiod_status].len = 5;
+
+       d[SI_decoder_flags].prefix = "[";
+       d[SI_decoder_flags].postfix = "]";
+       d[SI_decoder_flags].color.fg = COLOR_MAGENTA;
+       d[SI_decoder_flags].color.bg = COLOR_BLACK;
+       d[SI_decoder_flags].align = CENTER;
+       d[SI_decoder_flags].x = 5;
+       d[SI_decoder_flags].y = 27;
+       d[SI_decoder_flags].len = 10;
+
+       d[SI_mtime].prefix = "mod: ";
+       d[SI_mtime].postfix = "";
+       d[SI_mtime].color.fg = COLOR_MAGENTA;
+       d[SI_mtime].color.bg = COLOR_BLACK;
+       d[SI_mtime].align = CENTER;
+       d[SI_mtime].x = 15;
+       d[SI_mtime].y = 27;
+       d[SI_mtime].len = 22;
+
+       d[SI_file_size].prefix = "";
+       d[SI_file_size].postfix = "kb";
+       d[SI_file_size].color.fg = COLOR_MAGENTA;
+       d[SI_file_size].color.bg = COLOR_BLACK;
+       d[SI_file_size].align = CENTER;
+       d[SI_file_size].x = 37;
+       d[SI_file_size].y = 27;
+       d[SI_file_size].len = 10;
+
+       d[SI_channels].prefix = "";
+       d[SI_channels].postfix = "ch";
+       d[SI_channels].color.fg = COLOR_MAGENTA;
+       d[SI_channels].color.bg = COLOR_BLACK;
+       d[SI_channels].align = CENTER;
+       d[SI_channels].x = 47;
+       d[SI_channels].y = 27;
+       d[SI_channels].len = 5;
+
+       d[SI_last_played].prefix = "lp: ";
+       d[SI_last_played].postfix = "";
+       d[SI_last_played].color.fg = COLOR_MAGENTA;
+       d[SI_last_played].color.bg = COLOR_BLACK;
+       d[SI_last_played].align = CENTER;
+       d[SI_last_played].x = 52;
+       d[SI_last_played].y = 27;
+       d[SI_last_played].len = 21;
+
+       d[SI_num_chunks].prefix = "";
+       d[SI_num_chunks].postfix = "x";
+       d[SI_num_chunks].color.fg = COLOR_MAGENTA;
+       d[SI_num_chunks].color.bg = COLOR_BLACK;
+       d[SI_num_chunks].align = RIGHT;
+       d[SI_num_chunks].x = 73;
+       d[SI_num_chunks].y = 27;
+       d[SI_num_chunks].len = 11;
+
+       d[SI_chunk_time].prefix = "";
+       d[SI_chunk_time].postfix = "ms";
+       d[SI_chunk_time].color.fg = COLOR_MAGENTA;
+       d[SI_chunk_time].color.bg = COLOR_BLACK;
+       d[SI_chunk_time].align = LEFT;
+       d[SI_chunk_time].x = 84;
+       d[SI_chunk_time].y = 27;
+       d[SI_chunk_time].len = 8;
+
+       d[SI_amplification].prefix = "amp:";
+       d[SI_amplification].postfix = "";
+       d[SI_amplification].color.fg = COLOR_MAGENTA;
+       d[SI_amplification].color.bg = COLOR_BLACK;
+       d[SI_amplification].align = RIGHT;
+       d[SI_amplification].x = 92;
+       d[SI_amplification].y = 27;
+       d[SI_amplification].len = 8;
+
+       d[SI_techinfo].prefix = "";
+       d[SI_techinfo].postfix = "";
+       d[SI_techinfo].color.fg = COLOR_GREEN;
+       d[SI_techinfo].color.bg = COLOR_BLACK;
+       d[SI_techinfo].align = CENTER;
+       d[SI_techinfo].x = 0;
+       d[SI_techinfo].y = 43;
+       d[SI_techinfo].len = 100;
+
+       d[SI_title].prefix = "";
+       d[SI_title].postfix = ",";
+       d[SI_title].color.fg = COLOR_GREEN;
+       d[SI_title].color.bg = COLOR_BLACK;
+       d[SI_title].align = RIGHT;
+       d[SI_title].x = 0;
+       d[SI_title].y = 53;
+       d[SI_title].len = 45;
+
+       d[SI_artist].prefix = " by ";
+       d[SI_artist].postfix = "";
+       d[SI_artist].color.fg = COLOR_GREEN;
+       d[SI_artist].color.bg = COLOR_BLACK;
+       d[SI_artist].align = LEFT;
+       d[SI_artist].x = 45;
+       d[SI_artist].y = 53;
+       d[SI_artist].len = 45;
+
+       d[SI_year].prefix = "(";
+       d[SI_year].postfix = ")";
+       d[SI_year].color.fg = COLOR_GREEN;
+       d[SI_year].color.bg = COLOR_BLACK;
+       d[SI_year].align = RIGHT;
+       d[SI_year].x = 90;
+       d[SI_year].y = 53;
+       d[SI_year].len = 10;
+
+       d[SI_album].prefix = "A: ";
+       d[SI_album].postfix = ",";
+       d[SI_album].color.fg = COLOR_GREEN;
+       d[SI_album].color.bg = COLOR_BLACK;
+       d[SI_album].align = RIGHT;
+       d[SI_album].x = 0;
+       d[SI_album].y = 63;
+       d[SI_album].len = 50;
+
+       d[SI_comment].prefix = " C: ";
+       d[SI_comment].postfix = "";
+       d[SI_comment].color.fg = COLOR_GREEN;
+       d[SI_comment].color.bg = COLOR_BLACK;
+       d[SI_comment].align = LEFT;
+       d[SI_comment].x = 50;
+       d[SI_comment].y = 63;
+       d[SI_comment].len = 50;
+
+       d[SI_afs_mode].prefix = "";
+       d[SI_afs_mode].postfix = "";
+       d[SI_afs_mode].color.fg = COLOR_YELLOW;
+       d[SI_afs_mode].color.bg = COLOR_BLACK;
+       d[SI_afs_mode].align = CENTER;
+       d[SI_afs_mode].x = 0;
+       d[SI_afs_mode].y = 77;
+       d[SI_afs_mode].len = 100;
+
+       d[SI_attributes_txt].prefix = "";
+       d[SI_attributes_txt].postfix = "";
+       d[SI_attributes_txt].color.fg = COLOR_YELLOW;
+       d[SI_attributes_txt].color.bg = COLOR_BLACK;
+       d[SI_attributes_txt].align = CENTER;
+       d[SI_attributes_txt].x = 0;
+       d[SI_attributes_txt].y = 87;
+       d[SI_attributes_txt].len = 100;
+
+       d[SI_directory].prefix = "dir: ";
+       d[SI_directory].postfix = "";
+       d[SI_directory].color.fg = COLOR_YELLOW;
+       d[SI_directory].color.bg = COLOR_BLACK;
+       d[SI_directory].align = CENTER;
+       d[SI_directory].x = 0;
+       d[SI_directory].y = 97;
+       d[SI_directory].len = 100;
 }
 
 struct theme_description {
diff --git a/mood.c b/mood.c
index 584c46b..c06f695 100644 (file)
--- a/mood.c
+++ b/mood.c
@@ -93,32 +93,60 @@ struct mood {
  */
 static struct mood *current_mood;
 
-/**
- * Rough approximation to sqrt.
+/*
+ * Find the position of the most-significant set bit.
  *
- * \param x Integer of which to calculate the sqrt.
+ * Copied and slightly adapted from the linux source tree, version 4.9.39
+ * (2017-07).
+ */
+__a_const static uint32_t fls64(uint64_t v)
+{
+       int n = 63;
+       const uint64_t ones = ~(uint64_t)0U;
+
+       if ((v & (ones << 32)) == 0) {
+               n -= 32;
+               v <<= 32;
+       }
+       if ((v & (ones << (64 - 16))) == 0) {
+               n -= 16;
+               v <<= 16;
+       }
+       if ((v & (ones << (64 - 8))) == 0) {
+               n -= 8;
+               v <<= 8;
+       }
+       if ((v & (ones << (64 - 4))) == 0) {
+               n -= 4;
+               v <<= 4;
+       }
+       if ((v & (ones << (64 - 2))) == 0) {
+               n -= 2;
+               v <<= 2;
+       }
+       if ((v & (ones << (64 - 1))) == 0)
+               n -= 1;
+       return n;
+}
+
+/*
+ * Compute the integer square root floor(sqrt(x)).
  *
- * \return An integer res with res * res <= x.
+ * Taken 2007 from the linux source tree.
  */
 __a_const static uint64_t int_sqrt(uint64_t x)
 {
-       uint64_t op, res, one = 1;
-       op = x;
-       res = 0;
-
-       one = one << 62;
-       while (one > op)
-               one >>= 2;
+       uint64_t op = x, res = 0, one = 1;
 
+       one = one << (fls64(x) & ~one);
        while (one != 0) {
                if (op >= res + one) {
                        op = op - (res + one);
-                       res = res +  2 * one;
+                       res = res + 2 * one;
                }
                res /= 2;
                one /= 4;
        }
-//     PARA_NOTICE_LOG("sqrt(%llu) = %llu\n", x, res);
        return res;
 }
 
index cb0611e..8d8cadc 100644 (file)
--- a/ogg_afh.c
+++ b/ogg_afh.c
@@ -66,45 +66,24 @@ static int ogg_vorbis_get_file_info(char *map, size_t numbytes, __a_unused int f
 {
        int ret;
        struct private_vorbis_data pvd;
-       struct ogg_afh_callback_info vorbis_callback_info = {
+       struct oac_callback_info vorbis_callback_info = {
                .packet_callback = vorbis_packet_callback,
                .private_data = &pvd,
        };
 
        vorbis_info_init(&pvd.vi);
        vorbis_comment_init(&pvd.vc);
-       ret = ogg_get_file_info(map, numbytes, afhi, &vorbis_callback_info);
+       ret = oac_get_file_info(map, numbytes, afhi, &vorbis_callback_info);
        vorbis_info_clear(&pvd.vi);
        vorbis_comment_clear(&pvd.vc);
        return ret;
 }
 
-struct vorbis_get_header_data {
-       ogg_stream_state os;
-       char *buf;
-       size_t len;
-};
-
-static void add_ogg_page(ogg_page *og, struct vorbis_get_header_data *vghd)
-{
-       size_t old_len = vghd->len;
-       size_t new_len = vghd->len + og->header_len + og->body_len;
-       char *buf = para_realloc(vghd->buf, new_len), *p = buf + old_len;
-
-       memcpy(p, og->header, og->header_len);
-       memcpy(p + og->header_len, og->body, og->body_len);
-       vghd->buf = buf;
-       vghd->len = new_len;
-       PARA_DEBUG_LOG("header/body/old/new: %li/%li/%zu/%zu\n",
-               og->header_len, og->body_len, old_len, new_len);
-}
-
 static int vorbis_get_header_callback(ogg_packet *packet, int packet_num,
                int serial, __a_unused struct afh_info *afhi, void *private_data)
 {
        int ret;
-       struct vorbis_get_header_data *vghd = private_data;
-       ogg_page og;
+       struct oac_custom_header *h = private_data;
        static unsigned char dummy_packet[] = {
                0x03,
                'v', 'o', 'r', 'b', 'i', 's',
@@ -115,17 +94,12 @@ static int vorbis_get_header_callback(ogg_packet *packet, int packet_num,
        };
 
        PARA_DEBUG_LOG("processing ogg packet #%d\n", packet_num);
-       if (packet_num > 2)
-               return 0;
        if (packet_num == 0) {
-               ogg_stream_init(&vghd->os, serial);
-               ret = ogg_stream_packetin(&vghd->os, packet);
+               oac_custom_header_init(serial, h);
+               ret = oac_custom_header_append(packet, h);
                if (ret < 0)
-                       goto out;
-               ret = -E_OGG_STREAM_FLUSH;
-               if (ogg_stream_flush(&vghd->os, &og) == 0)
-                       goto out;
-               add_ogg_page(&og, vghd);
+                       return ret;
+               oac_custom_header_flush(h);
                return 1;
        }
        if (packet_num == 1) {
@@ -133,42 +107,37 @@ static int vorbis_get_header_callback(ogg_packet *packet, int packet_num,
                PARA_INFO_LOG("replacing metadata packet\n");
                replacement.packet = dummy_packet;
                replacement.bytes = sizeof(dummy_packet);
-               ret = ogg_stream_packetin(&vghd->os, &replacement);
-               if (ret >= 0)
-                       return 1;
-               ret = -E_OGG_PACKET_IN;
-               goto out;
+               ret = oac_custom_header_append(&replacement, h);
+               return ret < 0? ret : 1;
        }
-       ret = -E_OGG_PACKET_IN;
-       if (ogg_stream_packetin(&vghd->os, packet) < 0)
-               goto out;
-       while (ogg_stream_flush(&vghd->os, &og))
-               add_ogg_page(&og, vghd);
-       ret = 0;
-out:
-       ogg_stream_clear(&vghd->os);
-       return ret;
+       assert(packet_num == 2);
+       ret = oac_custom_header_append(packet, h);
+       if (ret < 0)
+               return ret;
+       oac_custom_header_flush(h);
+       return 0;
 }
 
 static void vorbis_get_header(void *map, size_t mapsize, char **buf,
                size_t *len)
 {
        int ret;
-       struct vorbis_get_header_data vghd = {.len = 0};
-       struct ogg_afh_callback_info cb = {
+       struct oac_custom_header *h = oac_custom_header_new();
+       struct oac_callback_info cb = {
                .packet_callback = vorbis_get_header_callback,
-               .private_data = &vghd,
+               .private_data = h,
        };
 
-       ret = ogg_get_file_info(map, mapsize, NULL, &cb);
-       if (ret < 0)
-               goto fail;
-       *buf = vghd.buf;
-       *len = vghd.len;
-       PARA_INFO_LOG("created %zu byte ogg vorbis header\n", *len);
-       return;
-fail:
-       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+       ret = oac_get_file_info(map, mapsize, NULL, &cb);
+       *len = oac_custom_header_get(buf, h);
+       if (ret < 0) {
+               PARA_ERROR_LOG("could not create ogg/vorbis header: %s\n",
+                       para_strerror(-ret));
+               free(*buf);
+               *buf = NULL;
+               *len = 0;
+       } else
+               PARA_INFO_LOG("created %zu byte ogg vorbis header\n", *len);
 }
 
 static int vorbis_make_meta_packet(struct taginfo *tags, ogg_packet *result)
@@ -199,7 +168,7 @@ static int vorbis_rewrite_tags(const char *map, size_t mapsize,
        ret = vorbis_make_meta_packet(tags, &packet);
        if (ret < 0)
                return ret;
-       ret = ogg_rewrite_tags(map, mapsize, output_fd, (char *)packet.packet,
+       ret = oac_rewrite_tags(map, mapsize, output_fd, (char *)packet.packet,
                packet.bytes);
        free(packet.packet);
        return ret;
index 734fd58..eb90c5f 100644 (file)
@@ -19,7 +19,7 @@
 /* Taken from decoder_example.c of libvorbis-1.2.3. */
 static int process_packets_2_and_3(ogg_sync_state *oss,
                ogg_stream_state *stream, struct afh_info *afhi,
-               struct ogg_afh_callback_info *ci)
+               struct oac_callback_info *ci)
 {
        ogg_page page;
        ogg_packet packet;
@@ -60,7 +60,7 @@ static int process_packets_2_and_3(ogg_sync_state *oss,
 }
 
 static int process_ogg_packets(ogg_sync_state *oss, struct afh_info *afhi,
-               struct ogg_afh_callback_info *ci)
+               struct oac_callback_info *ci)
 {
        ogg_packet packet;
        ogg_stream_state stream;
@@ -122,8 +122,8 @@ static void set_chunk_tv(int frames_per_chunk, int frequency,
  *
  * \return Standard.
  */
-int ogg_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
-               struct ogg_afh_callback_info *ci)
+int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
+               struct oac_callback_info *ci)
 {
        ogg_sync_state oss;
        ogg_page op;
@@ -216,7 +216,7 @@ static int write_ogg_page(int fd, const ogg_page *op)
  *
  * \return Standard.
  */
-int ogg_rewrite_tags(const char *map, size_t map_sz, int fd,
+int oac_rewrite_tags(const char *map, size_t map_sz, int fd,
                char *meta_packet, size_t meta_sz)
 {
        ogg_sync_state oss_in, oss_out;
@@ -332,3 +332,108 @@ out:
                ogg_stream_clear(so);
        return ret;
 }
+
+/* Structure for providing custom headers for streaming. */
+struct oac_custom_header {
+       char *buf;
+       size_t len;
+       ogg_stream_state oss;
+};
+
+/**
+ * Allocate and return a custom header structure.
+ *
+ * For some audio codecs which employ the ogg container format, the server side
+ * wants to replace the meta tags at the beginning of the file because they are
+ * not needed for streaming and can be arbitrary large. The structure returned
+ * by this function is typically used as the ->private field of struct \ref
+ * oac_callback_info for \ref oac_get_file_info(). This allows the audio format
+ * handler to set up a custom header which is identical to the original header,
+ * but with the meta data part replaced by fixed length dummy contents.
+ *
+ * \return The returned memory must be initialized with the serial number of
+ * the ogg stream before ogg packets can be submitted to it. This is not done
+ * here because the header structure is allocated before \ref
+ * oac_get_file_info() is called, and the serial number is not known at this
+ * point.
+ *
+ * \sa \ref oac_custom_header_init().
+ */
+struct oac_custom_header *oac_custom_header_new(void)
+{
+       return para_calloc(sizeof(struct oac_custom_header));
+}
+
+/**
+ * Set the serial number of an allocated header structure.
+ *
+ * \param serial Passed to the callback function.
+ * \param h As returned from \ref oac_custom_header_new().
+ *
+ * This function must be called before any packets are submitted.
+ */
+void oac_custom_header_init(int serial, struct oac_custom_header *h)
+{
+       ogg_stream_init(&h->oss, serial);
+}
+
+/**
+ * Submit an ogg packet to a custom header structure.
+ *
+ * \param op The packet to append.
+ * \param h Must be initialized.
+ *
+ * The packet may be the one which was passed to the callback, or a completely
+ * different one, like a dummy metadata packet.
+ *
+ * \return Standard.
+ */
+int oac_custom_header_append(ogg_packet *op, struct oac_custom_header *h)
+{
+       return ogg_stream_packetin(&h->oss, op) < 0? -E_OGG_PACKET_IN : 1;
+}
+
+/**
+ * Force remaining packets into an ogg page.
+ *
+ * \param h Should contain submitted but not yet flushed packets.
+ *
+ * This is called after the first packet has been submitted with \ref
+ * oac_custom_header_append() to make sure the first ogg page contains only
+ * this packet. Also when header processing is complete, the callbacks call
+ * this to force the previously submitted packets into a page.
+ */
+void oac_custom_header_flush(struct oac_custom_header *h)
+{
+       ogg_page og;
+
+       while (ogg_stream_flush(&h->oss, &og)) {
+               size_t len = og.header_len + og.body_len;
+               h->buf = para_realloc(h->buf, h->len + len);
+               memcpy(h->buf + h->len, og.header, og.header_len);
+               memcpy(h->buf + h->len + og.header_len, og.body, og.body_len);
+               h->len += len;
+       }
+}
+
+/**
+ * Return the custom header buffer and deallocate resources.
+ *
+ * This is called after the ogg packets which comprise the header have been
+ * submitted and flushed.
+ *
+ * \param buf Result pointer.
+ * \param h Must not be used any more after the call.
+ *
+ * \return The size of the header. This is the sum of the sizes of all ogg
+ * pages that have been flushed out.
+ */
+size_t oac_custom_header_get(char **buf, struct oac_custom_header *h)
+{
+       size_t ret = h->len;
+
+       *buf = h->buf;
+       ogg_stream_clear(&h->oss);
+       free(h);
+       return ret;
+}
index 7b9d131..8f3494a 100644 (file)
@@ -9,6 +9,12 @@
  * handlers that use the ogg container format.
  */
 
+struct oac_custom_header *oac_custom_header_new(void);
+void oac_custom_header_init(int serial, struct oac_custom_header *h);
+int oac_custom_header_append(ogg_packet *op, struct oac_custom_header *h);
+void oac_custom_header_flush(struct oac_custom_header *h);
+size_t oac_custom_header_get(char **buf, struct oac_custom_header *h);
+
 /**
  * Callback structure provided by audio format handlers.
  *
@@ -16,7 +22,7 @@
  * function whose purpose is to extract the meta information about the audio
  * file from the first few ogg packets of the bitstream.
  */
-struct ogg_afh_callback_info {
+struct oac_callback_info {
        /**
         * ogg_get_file_info() calls this function for the first three ogg
         * packets, or until the callback returns a non-positive value. If it
@@ -33,7 +39,7 @@ struct ogg_afh_callback_info {
        void *private_data;
 };
 
-int ogg_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
-               struct ogg_afh_callback_info *ci);
-int ogg_rewrite_tags(const char *map, size_t mapsize, int fd,
+int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
+               struct oac_callback_info *ci);
+int oac_rewrite_tags(const char *map, size_t mapsize, int fd,
                char *meta_packet, size_t meta_sz);
index 64eeb03..5341924 100644 (file)
@@ -84,6 +84,14 @@ static int opus_get_comments(char *comments, int length,
        return 1;
 }
 
+/*
+ * Ogg/Opus has two mandatory header packets:
+ *
+ * 1. ID header (identifies the stream as Opus). Dedicated "BOS" ogg page.
+ * 2. Comment header (metadata). May span multiple pages.
+ *
+ * See doc/draft-ietf-codec-oggopus.xml in the opus source tree for details.
+ */
 static int opus_packet_callback(ogg_packet *packet, int packet_num,
                __a_unused int serial, struct afh_info *afhi,
                void *private_data)
@@ -123,11 +131,11 @@ static int opus_get_file_info(char *map, size_t numbytes, __a_unused int fd,
        int ret, ms;
        struct opus_header oh = {.version = 0};
 
-       struct ogg_afh_callback_info opus_callback_info = {
+       struct oac_callback_info opus_callback_info = {
                .packet_callback = opus_packet_callback,
                .private_data = &oh,
        };
-       ret = ogg_get_file_info(map, numbytes, afhi, &opus_callback_info);
+       ret = oac_get_file_info(map, numbytes, afhi, &opus_callback_info);
        if (ret < 0)
                return ret;
        ret = (afhi->chunk_table[afhi->chunks_total] - afhi->chunk_table[0]) * 8; /* bits */
@@ -222,11 +230,70 @@ static int opus_rewrite_tags(const char *map, size_t mapsize,
        int ret;
 
        meta_sz = opus_make_meta_packet(tags, &meta_packet);
-       ret = ogg_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
+       ret = oac_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
        free(meta_packet);
        return ret;
 }
 
+/*
+ * See doc/draft-ietf-codec-oggopus.xml in the opus source tree for details
+ * about the format of the comment header.
+ */
+static int opus_get_header_callback(ogg_packet *packet, int packet_num,
+               int serial, __a_unused struct afh_info *afhi, void *private_data)
+{
+       struct oac_custom_header *h = private_data;
+       int ret;
+       static unsigned char dummy_tags[] = { /* a minimal comment header */
+               'O', 'p', 'u', 's', 'T', 'a', 'g', 's',
+               0x06, 0x00, 0x00, 0x00, /* vendor string length */
+               'd', 'u', 'm', 'm', 'y', '\0', /* vendor string */
+               0x00, 0x00, 0x00, 0x00, /* user comment list length */
+       };
+       ogg_packet replacement;
+
+       if (packet_num == 0) {
+               oac_custom_header_init(serial, h);
+               ret = oac_custom_header_append(packet, h);
+               if (ret < 0)
+                       return ret;
+               oac_custom_header_flush(h);
+               return 1;
+       }
+       assert(packet_num == 1);
+       PARA_INFO_LOG("replacing metadata packet\n");
+       replacement = *packet;
+       replacement.packet = dummy_tags;
+       replacement.bytes = sizeof(dummy_tags);
+       ret = oac_custom_header_append(&replacement, h);
+       if (ret < 0)
+               return ret;
+       oac_custom_header_flush(h);
+       return 0;
+}
+
+static void opus_get_header(void *map, size_t mapsize, char **buf,
+               size_t *len)
+{
+       int ret;
+       struct oac_custom_header *h = oac_custom_header_new();
+       struct oac_callback_info cb = {
+               .packet_callback = opus_get_header_callback,
+               .private_data = h,
+       };
+
+       ret = oac_get_file_info(map, mapsize, NULL, &cb);
+       *len = oac_custom_header_get(buf, h);
+       if (ret < 0) {
+               PARA_ERROR_LOG("could not create custom header: %s\n",
+                       para_strerror(-ret));
+               free(*buf);
+               *buf = NULL;
+               *len = 0;
+       } else
+               PARA_INFO_LOG("created %zu byte ogg/opus header\n", *len);
+}
+
 /**
  * The init function of the ogg/opus audio format handler.
  *
@@ -235,6 +302,7 @@ static int opus_rewrite_tags(const char *map, size_t mapsize,
 void opus_afh_init(struct audio_format_handler *afh)
 {
        afh->get_file_info = opus_get_file_info,
+       afh->get_header = opus_get_header;
        afh->suffixes = opus_suffixes;
        afh->rewrite_tags = opus_rewrite_tags;
 }
diff --git a/para.h b/para.h
index 3cd1b16..323a4fb 100644 (file)
--- a/para.h
+++ b/para.h
@@ -103,15 +103,6 @@ void compute_chunk_time(long unsigned chunk_num,
                struct timeval *result);
 struct timeval *clock_get_realtime(struct timeval *tv);
 
-/** The enum of all status items. */
-enum status_items {STATUS_ITEM_ENUM NUM_STAT_ITEMS};
-extern const char *status_item_list[];
-/** Loop over each status item. */
-#define FOR_EACH_STATUS_ITEM(i) for (i = 0; i < NUM_STAT_ITEMS; i++)
-int for_each_stat_item(char *item_buf, size_t num_bytes,
-       int (*item_handler)(int, char *));
-
-
 /**
  * Return a random non-negative integer in an interval.
  *
@@ -233,3 +224,57 @@ enum loglevels {LOGLEVELS, NUM_LOGLEVELS};
 #define PARA_ERROR_LOG(f,...) para_log(LL_ERROR, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
 #define PARA_CRIT_LOG(f,...) para_log(LL_CRIT, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
 #define PARA_EMERG_LOG(f,...) para_log(LL_EMERG, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+
+#define STATUS_ITEMS \
+       STATUS_ITEM(basename) \
+       STATUS_ITEM(status) \
+       STATUS_ITEM(num_played) \
+       STATUS_ITEM(mtime) \
+       STATUS_ITEM(bitrate) \
+       STATUS_ITEM(frequency) \
+       STATUS_ITEM(file_size) \
+       STATUS_ITEM(status_flags) \
+       STATUS_ITEM(format) \
+       STATUS_ITEM(score) \
+       STATUS_ITEM(techinfo) \
+       STATUS_ITEM(afs_mode) \
+       STATUS_ITEM(attributes_txt) \
+       STATUS_ITEM(decoder_flags) \
+       STATUS_ITEM(audiod_status) \
+       STATUS_ITEM(play_time) \
+       STATUS_ITEM(attributes_bitmap) \
+       STATUS_ITEM(offset) \
+       STATUS_ITEM(seconds_total) \
+       STATUS_ITEM(stream_start) \
+       STATUS_ITEM(current_time) \
+       STATUS_ITEM(audiod_uptime) \
+       STATUS_ITEM(image_id) \
+       STATUS_ITEM(lyrics_id) \
+       STATUS_ITEM(duration) \
+       STATUS_ITEM(directory) \
+       STATUS_ITEM(lyrics_name) \
+       STATUS_ITEM(image_name) \
+       STATUS_ITEM(path) \
+       STATUS_ITEM(hash) \
+       STATUS_ITEM(channels) \
+       STATUS_ITEM(last_played) \
+       STATUS_ITEM(num_chunks) \
+       STATUS_ITEM(chunk_time) \
+       STATUS_ITEM(amplification) \
+       STATUS_ITEM(artist) \
+       STATUS_ITEM(title) \
+       STATUS_ITEM(year) \
+       STATUS_ITEM(album) \
+       STATUS_ITEM(comment) \
+       STATUS_ITEM(max_chunk_size) \
+
+#define STATUS_ITEM(_name) SI_ ##_name,
+enum status_items {STATUS_ITEMS NUM_STAT_ITEMS};
+#undef STATUS_ITEM
+#define STATUS_ITEM(_name) #_name,
+
+extern const char *status_item_list[];
+/** Loop over each status item. */
+#define FOR_EACH_STATUS_ITEM(i) for (i = 0; i < NUM_STAT_ITEMS; i++)
+int for_each_stat_item(char *item_buf, size_t num_bytes,
+       int (*item_handler)(int, char *));
index 4e10c2e..00704b2 100644 (file)
@@ -6,61 +6,63 @@
 
 /** \file portable_io.h Inline functions for binary IO. */
 
-static inline uint64_t read_portable(unsigned bits, const char *buf)
+static inline uint64_t read_portable(unsigned bits, const void *buf)
 {
        uint64_t ret = 0;
        int i, num_bytes = bits / 8;
+       const uint8_t *p = (typeof(p))buf;
 
        for (i = 0; i < num_bytes; i++) {
-               unsigned char c = buf[i];
+               unsigned char c = p[i];
                ret += ((uint64_t)c << (8 * i));
        }
        return ret;
 }
 
-static inline uint64_t read_portable_be(unsigned bits, const char *buf)
+static inline uint64_t read_portable_be(unsigned bits, const void *buf)
 {
        uint64_t ret = 0;
        int i, num_bytes = bits / 8;
+       const uint8_t *p = (typeof(p))buf;
 
        for (i = 0; i < num_bytes; i++) {
-               unsigned char c = buf[i];
+               unsigned char c = p[i];
                ret += ((uint64_t)c << (8 * (num_bytes - i - 1)));
        }
        return ret;
 }
 
-static inline uint64_t read_u64(const char *buf)
+static inline uint64_t read_u64(const void *buf)
 {
        return read_portable(64, buf);
 }
 
-static inline uint32_t read_u32(const char *buf)
+static inline uint32_t read_u32(const void *buf)
 {
        return read_portable(32, buf);
 }
 
-static inline uint16_t read_u16(const char *buf)
+static inline uint16_t read_u16(const void *buf)
 {
        return read_portable(16, buf);
 }
 
-static inline uint8_t read_u8(const char *buf)
+static inline uint8_t read_u8(const void *buf)
 {
        return read_portable(8, buf);
 }
 
-static inline uint64_t read_u64_be(const char *buf)
+static inline uint64_t read_u64_be(const void *buf)
 {
        return read_portable_be(64, buf);
 }
 
-static inline uint32_t read_u32_be(const char *buf)
+static inline uint32_t read_u32_be(const void *buf)
 {
        return read_portable_be(32, buf);
 }
 
-static inline uint16_t read_u16_be(const char *buf)
+static inline uint16_t read_u16_be(const void *buf)
 {
        return read_portable_be(16, buf);
 }
@@ -68,8 +70,10 @@ static inline uint16_t read_u16_be(const char *buf)
 static inline void write_portable(unsigned bits, char *buf, uint64_t val)
 {
        int i, num_bytes = bits / 8;
+       uint8_t *p = (typeof(p))buf;
+
        for (i = 0; i < num_bytes; i++) {
-               buf[i] = val & 0xff;
+               p[i] = val & 0xff;
                val = val >> 8;
        }
 }
@@ -77,43 +81,45 @@ static inline void write_portable(unsigned bits, char *buf, uint64_t val)
 static inline void write_portable_be(unsigned bits, char *buf, uint64_t val)
 {
        int i, num_bytes = bits / 8;
+       uint8_t *p = (typeof(p))buf;
+
        for (i = 0; i < num_bytes; i++) {
-               buf[num_bytes - i - 1] = val & 0xff;
+               p[num_bytes - i - 1] = val & 0xff;
                val = val >> 8;
        }
 }
 
-static inline void write_u64(char *buf, uint64_t val)
+static inline void write_u64(void *buf, uint64_t val)
 {
        write_portable(64, buf, val);
 }
 
-static inline void write_u32(char *buf, uint32_t val)
+static inline void write_u32(void *buf, uint32_t val)
 {
        write_portable(32, buf, (uint64_t) val);
 }
 
-static inline void write_u16(char *buf, uint16_t val)
+static inline void write_u16(void *buf, uint16_t val)
 {
        write_portable(16, buf, (uint64_t) val);
 }
 
-static inline void write_u8(char *buf, uint8_t val)
+static inline void write_u8(void *buf, uint8_t val)
 {
        write_portable(8, buf, (uint64_t) val);
 }
 
-static inline void write_u64_be(char *buf, uint64_t val)
+static inline void write_u64_be(void *buf, uint64_t val)
 {
        write_portable_be(64, buf, val);
 }
 
-static inline void write_u32_be(char *buf, uint32_t val)
+static inline void write_u32_be(void *buf, uint32_t val)
 {
        write_portable_be(32, buf, (uint64_t) val);
 }
 
-static inline void write_u16_be(char *buf, uint16_t val)
+static inline void write_u16_be(void *buf, uint16_t val)
 {
        write_portable_be(16, buf, (uint64_t) val);
 }
index 4e318af..cd65ac5 100644 (file)
--- a/spx_afh.c
+++ b/spx_afh.c
@@ -152,13 +152,13 @@ static int spx_get_file_info(char *map, size_t numbytes, __a_unused int fd,
                struct afh_info *afhi)
 {
        struct private_spx_data psd;
-       struct ogg_afh_callback_info spx_callback_info = {
+       struct oac_callback_info spx_callback_info = {
                .packet_callback = spx_packet_callback,
                .private_data = &psd,
        };
 
        memset(&psd, 0, sizeof(psd));
-       return ogg_get_file_info(map, numbytes, afhi, &spx_callback_info);
+       return oac_get_file_info(map, numbytes, afhi, &spx_callback_info);
 }
 
 static size_t spx_make_meta_packet(struct taginfo *tags, char **result)
@@ -244,7 +244,7 @@ static int spx_rewrite_tags(const char *map, size_t mapsize,
        int ret;
 
        meta_sz = spx_make_meta_packet(tags, &meta_packet);
-       ret = ogg_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
+       ret = oac_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
        free(meta_packet);
        return ret;
 }
index 904ac18..fb3a05f 100644 (file)
@@ -330,7 +330,7 @@ code repository, execute
 
                git clone git://git.tuebingen.mpg.de/osl
 
-- [openssl](http://www.openssl.org/) or
+- [openssl](https://www.openssl.org/) or
 [libgcrypt](ftp://ftp.gnupg.org/gcrypt/libgcrypt/).  At least one
 of these two libraries is needed as the backend for cryptographic
 routines on both the server and the client side. Both openssl and
@@ -349,12 +349,12 @@ is called `libmad0-dev` on debian-based systems. Note that libmad is
 not necessary on the server side, i.e., for sending MP3 files.
 
 - [libid3tag](http://www.underbit.com/products/mad/). For version-2
-ID3 tag support, you willl need the libid3tag development package
+ID3 tag support, you will need the libid3tag development package
 `libid3tag0-dev`. Without libid3tag, only version-1 tags are
 recognized. The mp3 tagger also needs this library for modifying
 (id3v1 and id3v2) tags.
 
-- [ogg vorbis](http://www.xiph.org/downloads/). For ogg vorbis streams
+- [ogg vorbis](https://www.xiph.org/downloads/). For ogg vorbis streams
 you need libogg, libvorbis, libvorbisfile. The corresponding Debian
 packages are called `libogg-dev` and `libvorbis-dev`.
 
@@ -364,10 +364,10 @@ that for some distributions, e.g. Ubuntu, mp4ff is not part of the
 libfaad package. Install the faad library from sources (available
 through the above link) to get the mp4ff library and header files.
 
-- [speex](http://www.speex.org/). In order to stream or decode speex
+- [speex](https://www.speex.org/). In order to stream or decode speex
 files, libspeex (`libspeex-dev`) is required.
 
-- [flac](http://flac.sourceforge.net/). To stream or decode files
+- [flac](https://xiph.org/flac/). To stream or decode files
 encoded with the _Free Lossless Audio Codec_, libFLAC (`libFLAC-dev`)
 must be installed.
 
@@ -378,7 +378,7 @@ installed. Debian package: `libsamplerate-dev`.
 - [alsa-lib](ftp://ftp.alsa-project.org/pub/lib/). On Linux, you will
 need to have the ALSA development package `libasound2-dev` installed.
 
-- [libao](http://downloads.xiph.org/releases/ao/). Needed to build
+- [libao](https://ftp.osuosl.org/pub/xiph/releases/ao/). Needed to build
 the ao writer (ESD, PulseAudio,...).  Debian package: `libao-dev`.
 
 - [curses](ftp://ftp.gnu.org/pub/gnu/ncurses). Needed for
@@ -1439,7 +1439,7 @@ only for Linux.
 
 - UDP. Recommended for multicast LAN streaming.
 
-See the Appendix on [network protocols](/#Network.protocols)
+See the Appendix on [network protocols](#Network.protocols)
 for brief descriptions of the various protocols relevant for network
 audio streaming with paraslash.
 
@@ -2007,7 +2007,7 @@ and for getting updates.
 the configure file which is shipped in the tarballs but has to be
 generated when compiling from git.
 
-- [discount](http://www.pell.portland.or.us/~orc/Code/discount). The
+- [discount](http://www.pell.portland.or.us/~orc/Code/discount/). The
 HTML version of this manual and some of the paraslash web pages are
 written in the Markdown markup language and are translated into html
 with the converter of the *Discount* package.
@@ -2111,7 +2111,7 @@ Coding Style
 
 The preferred coding style for paraslash coincides more or less
 with the style of the Linux kernel. So rather than repeating what is
-written [there](http://www.kernel.org/doc/Documentation/process/coding-style.rst),
+written [there](https://www.kernel.org/doc/Documentation/process/coding-style.rst),
 here are the most important points.
 
 - Burn the GNU coding standards.
@@ -2374,17 +2374,17 @@ Application web pages
 ---------------------
 
 - [paraslash](http://people.tuebingen.mpg.de/maan/paraslash/)
-- [xmms](http://xmms2.org/wiki/Main_Page)
+- [xmms](https://xmms2.org/wiki/Main_Page)
 - [mpg123](http://www.mpg123.de/)
-- [gstreamer](http://gstreamer.freedesktop.org/)
+- [gstreamer](https://gstreamer.freedesktop.org/)
 - [icecast](http://www.icecast.org/)
-- [Audio Compress](http://beesbuzz.biz/code/audiocompress.php)
+- [Audio Compress](https://beesbuzz.biz/code/audiocompress.php)
 
 External documentation
 ----------------------
 
 - [The mathematics of
-Raid6](http://kernel.org/pub/linux/kernel/people/hpa/raid6.pdf)
+Raid6](https://www.kernel.org/pub/linux/kernel/people/hpa/raid6.pdf)
 by H. Peter Anvin
 
 - [Effective Erasure Codes for reliable Computer Communication