]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'refs/heads/t/score-formula'
authorAndre Noll <maan@tuebingen.mpg.de>
Thu, 18 Nov 2021 15:23:20 +0000 (16:23 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Thu, 18 Nov 2021 15:24:29 +0000 (16:24 +0100)
A single patch which modifies the score function of the audio file
selector to re-scale the two quantities that comprise the score value.

Cooking for six months.

* refs/heads/t/score-formula:
  Rework score formula.

39 files changed:
INSTALL
Makefile.real
NEWS.md
aac_afh.c
afh.c
afh.h
afs.c
afs.h
aft.c
alsa_write.c
ao_write.c
audiod.c
buffer_tree.c
chunk_queue.c
client.c
client_common.c
close_on_fork.c
command.c
compress_filter.c
error.h
interactive.c
interactive.h
list.h
mood.c
net.c
oss_write.c
play.c
sched.c
send_common.c
server.c
string.h
sync_filter.c
udp_send.c
vss.c
web/documentation.in.html
web/download.in.html
web/manual.md
write.h
write_common.c

diff --git a/INSTALL b/INSTALL
index 4a86e967ee72955a32ed37e2fd88b849f808053e..45676b7ea44d0bb5cfc854272bdcbd5cf7a2e3a0 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -18,7 +18,7 @@ Installing paraslash from tarball
 
 Installing paraslash from git
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-       autoconf && autoheader && make && sudo make install
+       autoconf && autoheader && ./configure && make && sudo make install
 
 Example for cross-compiling
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
index ddf85b58d06a1b0b9c87a6d8d1890a8facbf5480..b88de22533048979bcfef8f3396b7608297afb3b 100644 (file)
@@ -20,7 +20,7 @@ uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS")
 uname_rs := $(shell uname -rs)
 cc_version := $(shell $(CC) --version | head -n 1)
 GIT_VERSION := $(shell ./GIT-VERSION-GEN git-version.h)
-COPYRIGHT_YEAR := 2020
+COPYRIGHT_YEAR := 2021
 
 ifeq ("$(origin O)", "command line")
        build_dir := $(O)
diff --git a/NEWS.md b/NEWS.md
index 3e3e7abfda28365cba7abfa2ead1c2c408d75801..073f26471a101310cc92e484f4c410aa64a6f9d2 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,56 @@
 NEWS
 ====
 
+---------------------------------------
+0.7.0 (to be announced) "seismic orbit"
+---------------------------------------
+
+- Paraslash writers handle early end-of-file more gracefully.
+- The alsa writer no longer warns about spurious underruns.
+- The score formula  of the audio file selector has been reworked.
+- Cleanups of the doubly linked lists code.
+
+--------------------------------------
+0.6.4 (2021-11-04) "fuzzy calibration"
+--------------------------------------
+
+This point release contains a fair number of fixes but no new features.
+This marks the end of the 0.6 development, although paraslash-0.6 will
+still be supported for some time and subsequent maintenance releases
+may follow.
+
+- The udp sender no longer crashes when empty chunks are encountered.
+- Fix a double-free bug in the exit path of the server.
+- The "jmp" command now errors out when given a negative percentage.
+- A fix for a bug in para_afh which triggered on the attempt to modify
+  the tags of an invalid mp4 file.
+- A memory leak in para_afh has been fixed.
+- The udp sender no longer sends multiple EOF packets.
+- Some gcc warnings have been silenced.
+- Minor log level adjustments and documentation improvements.
+
+Downloads:
+[tarball](./releases/paraslash-0.6.4.tar.xz),
+[signature](./releases/paraslash-0.6.4.tar.xz.asc)
+
+---------------------------------------
+0.5.9 (2021-11-04) "reversed dimension"
+---------------------------------------
+
+This release contains a few important fixes which have accumulated in
+the maint branch. The paraslash-0.5.x series has now reached its end
+of life and will no longer be supported. All users should upgrade to
+a more recent version at this point.
+
+- Fix an issue with the bash completion script.
+- Initialize the random seed also when using libgrypt.
+- Fix some compiler warnings in the resample filter
+- Don't return spurious errors from the ff server command.
+
+Downloads:
+[tarball](./releases/paraslash-0.5.9.tar.bz2),
+[signature](./releases/paraslash-0.5.9.tar.bz2.asc)
+
 ----------------------------------------
 0.6.3 (2021-02-18) "generalized activity"
 -----------------------------------------
index 7f2a22a223ce733aa4b49d0a60ff63d1b95bf321..2b3dd2cc538a57a233813b77adcb332bd77929ce 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
@@ -292,8 +292,7 @@ static int aac_afh_rewrite_tags(const char *map, size_t mapsize,
                mp4ff_tag_t *tag = metadata.tags + i;
 
                ret = -E_MP4FF_META_READ;
-               if (mp4ff_meta_get_by_index(mp4ff, i,
-                               &tag->item, &tag->value) < 0)
+               if (!mp4ff_meta_get_by_index(mp4ff, i, &tag->item, &tag->value))
                        goto free_tags;
                PARA_INFO_LOG("found: %s: %s\n", tag->item, tag->value);
                if (!strcmp(tag->item, "artist"))
@@ -318,7 +317,7 @@ static int aac_afh_rewrite_tags(const char *map, size_t mapsize,
        if (!found_comment)
                add_tag(&metadata, "comment", tags->comment);
        ret = -E_MP4FF_META_WRITE;
-       if (mp4ff_meta_update(&cb, &metadata) < 0)
+       if (!mp4ff_meta_update(&cb, &metadata))
                goto free_tags;
        ret = 1;
 free_tags:
diff --git a/afh.c b/afh.c
index 567b560a038f0923a663005b447a0fc688c57b2a..c896a7d1eff4a843e2e61a4ec8b6dac4982ed197 100644 (file)
--- a/afh.c
+++ b/afh.c
@@ -258,5 +258,6 @@ out:
                PARA_ERROR_LOG("%s\n", errctx);
        if (ret < 0)
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+       lls_free_parse_result(lpr, CMD_PTR);
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/afh.h b/afh.h
index 881db3c24217beff8d2885e1d62c05f3419aa404..b3295f6e2fda111bd30ec5d20cd2431bbea325a6 100644 (file)
--- a/afh.h
+++ b/afh.h
@@ -58,8 +58,6 @@ struct afh_info {
 
 /** Data about the current audio file, passed from afs to server. */
 struct audio_file_data {
-       /** The open file descriptor to the current audio file. */
-       int fd;
        /** Vss needs this for streaming. */
        struct afh_info afhi;
        /**
diff --git a/afs.c b/afs.c
index c4de2e8f37d5a94937f0fe3519715d40242f5329..3d86d1925e97517ee1222d9b3b04f46f541cc688 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -418,13 +418,13 @@ static int pass_afd(int fd, char *buf, size_t size)
  */
 static int open_next_audio_file(void)
 {
-       struct audio_file_data afd;
-       int ret, shmid;
+       int ret, shmid, fd;
        char buf[8];
 
-       ret = open_and_update_audio_file(&afd);
+       ret = open_and_update_audio_file(&fd);
        if (ret < 0) {
-               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+               if (ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND))
+                       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                goto no_admissible_files;
        }
        shmid = ret;
@@ -434,8 +434,8 @@ static int open_next_audio_file(void)
        }
        *(uint32_t *)buf = NEXT_AUDIO_FILE;
        *(uint32_t *)(buf + 4) = (uint32_t)shmid;
-       ret = pass_afd(afd.fd, buf, 8);
-       close(afd.fd);
+       ret = pass_afd(fd, buf, 8);
+       close(fd);
        if (ret >= 0)
                return ret;
 destroy:
@@ -981,7 +981,7 @@ __noreturn void afs_init(int socket_fd)
        int i, ret;
 
        register_signal_task(&s);
-       INIT_LIST_HEAD(&afs_client_list);
+       init_list_head(&afs_client_list);
        for (i = 0; i < NUM_AFS_TABLES; i++)
                afs_tables[i].init(&afs_tables[i]);
        ret = open_afs_tables();
diff --git a/afs.h b/afs.h
index cfa9cc6df4c11900739e9ff90fba0c4b30bf16e8..b1606493a05f047afb1e8ecb0fdd0a5bbcbafcfe 100644 (file)
--- a/afs.h
+++ b/afs.h
@@ -255,7 +255,7 @@ int attribute_check_callback(struct afs_callback_arg *aca);
 void aft_init(struct afs_table *t);
 int aft_get_row_of_path(const char *path, struct osl_row **row);
 int aft_check_attributes(uint64_t att_mask, struct para_buffer *pb);
-int open_and_update_audio_file(struct audio_file_data *afd);
+int open_and_update_audio_file(int *fd);
 int load_afd(int shmid, struct audio_file_data *afd);
 int get_afsi_of_row(const struct osl_row *row, struct afs_info *afsi);
 int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi);
diff --git a/aft.c b/aft.c
index b358c96cd9afd23bfa7f043c8add8bbf8b4bfade..c8c98e7ab679b5a5254eed9405afa3cca6cf870e 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -1024,7 +1024,14 @@ out:
 /**
  * Open the audio file with highest score and set up an afd structure.
  *
- * \param afd Result pointer.
+ * This determines and opens the next audio file, verifies that it did not
+ * change by comparing the recomputed the hash value of the file contents
+ * against the value stored in the audio file table. If all goes well, it
+ * creates a shared memory area containing the serialized version of the afd
+ * structure, including the chunk table, if any. The caller can then send the
+ * ID of this area and the open fd to the server process.
+ *
+ * \param fd Result pointer for the file descriptor of the audio file.
  *
  * On success, the numplayed field of the audio file selector info is increased
  * and the lastplayed time is set to the current time. Finally, the score of
@@ -1032,7 +1039,7 @@ out:
  *
  * \return Positive shmid on success, negative on errors.
  */
-int open_and_update_audio_file(struct audio_file_data *afd)
+int open_and_update_audio_file(int *fd)
 {
        unsigned char file_hash[HASH_SIZE];
        struct osl_object afsi_obj;
@@ -1042,6 +1049,7 @@ int open_and_update_audio_file(struct audio_file_data *afd)
        struct osl_object map, chunk_table_obj;
        struct ls_data *d = &status_item_ls_data;
        unsigned char *tmp_hash;
+       struct audio_file_data afd;
 again:
        ret = score_get_best(&current_aft_row, &d->score);
        if (ret < 0)
@@ -1074,11 +1082,11 @@ again:
        ret = load_afsi(&d->afsi, &afsi_obj);
        if (ret < 0)
                return ret;
-       ret = get_afhi_of_row(current_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;
+       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) {
@@ -1090,7 +1098,7 @@ again:
        } else {
                PARA_INFO_LOG("chunk table: %zu bytes\n", chunk_table_obj.size);
        }
-       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, fd);
        if (ret < 0)
                goto out;
        hash_function(map.data, map.size, file_hash);
@@ -1105,8 +1113,8 @@ again:
        new_afsi.last_played = time(NULL);
        save_afsi(&new_afsi, &afsi_obj); /* in-place update */
 
-       afd->audio_format_id = d->afsi.audio_format_id;
-       load_chunk_table(&afd->afhi, &chunk_table_obj);
+       afd.audio_format_id = d->afsi.audio_format_id;
+       load_chunk_table(&afd.afhi, &chunk_table_obj);
        aced.aft_row = current_aft_row;
        aced.old_afsi = &d->afsi;
        /*
@@ -1116,9 +1124,9 @@ again:
        ret = afs_event(AFSI_CHANGE, NULL, &aced);
        if (ret < 0)
                goto out;
-       ret = save_afd(afd);
+       ret = save_afd(&afd);
 out:
-       free(afd->afhi.chunk_table);
+       free(afd.afhi.chunk_table);
        if (chunk_table_obj.data)
                osl_close_disk_object(&chunk_table_obj);
        if (ret < 0) {
index bc06fc315bc51fb3fc1fa9729ae429b47a70d4b4..bbbf8b650ac86c4952ac46f22c166583018bfb88 100644 (file)
@@ -240,6 +240,8 @@ static void alsa_close(struct writer_node *wn)
 
        if (!pad)
                return;
+       if (!pad->handle)
+               goto free_pad;
        /*
         * It's OK to have a blocking operation here because we already made
         * sure that the PCM output buffer is (nearly) empty.
@@ -248,6 +250,7 @@ static void alsa_close(struct writer_node *wn)
        snd_pcm_drain(pad->handle);
        snd_pcm_close(pad->handle);
        snd_config_update_free_global();
+free_pad:
        free(pad);
 }
 
@@ -294,21 +297,23 @@ again:
                if (bytes == 0) /* no data available */
                        return 0;
                pad = wn->private_data = para_calloc(sizeof(*pad));
-               get_btr_sample_rate(btrn, &val);
+               ret = get_btr_sample_rate(btrn, &val);
+               if (ret < 0)
+                       goto err;
                pad->sample_rate = val;
-               get_btr_channels(btrn, &val);
+               ret = get_btr_channels(btrn, &val);
+               if (ret < 0)
+                       goto err;
                pad->channels = val;
-               get_btr_sample_format(btrn, &val);
+               ret = get_btr_sample_format(btrn, &val);
+               if (ret < 0)
+                       goto err;
                pad->sample_format = get_alsa_pcm_format(val);
-
                PARA_INFO_LOG("%u channel(s), %uHz\n", pad->channels,
                        pad->sample_rate);
                ret = alsa_init(wn);
-               if (ret < 0) {
-                       free(wn->private_data);
-                       wn->private_data = NULL;
+               if (ret < 0)
                        goto err;
-               }
                wn->min_iqs = pad->bytes_per_frame;
                goto again;
        }
@@ -326,7 +331,11 @@ again:
                goto again;
        }
        if (frames == -EPIPE) {
-               PARA_WARNING_LOG("underrun (tried to write %zu bytes)\n", bytes);
+               snd_pcm_status_t *status;
+               snd_pcm_status_malloc(&status);
+               if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN)
+                       PARA_WARNING_LOG("underrun\n");
+               snd_pcm_status_free(status);
                snd_pcm_prepare(pad->handle);
                return 0;
        }
index 447dea84c00a468330fe8229bfd70b74292264bd..037b92993325539552ddd625b881a843aa57c5a9 100644 (file)
@@ -357,9 +357,15 @@ static int aow_post_select(__a_unused struct sched *s, void *context)
                        goto remove_btrn;
                if (ret == 0)
                        return 0;
-               get_btr_sample_rate(wn->btrn, &rate);
-               get_btr_channels(wn->btrn, &ch);
-               get_btr_sample_format(wn->btrn, &format);
+               ret = get_btr_sample_rate(wn->btrn, &rate);
+               if (ret < 0)
+                       goto remove_btrn;
+               ret = get_btr_channels(wn->btrn, &ch);
+               if (ret < 0)
+                       goto remove_btrn;
+               ret = get_btr_sample_format(wn->btrn, &format);
+               if (ret < 0)
+                       goto remove_btrn;
                ret = aow_init(wn, rate, ch, format);
                if (ret < 0)
                        goto remove_btrn;
index a5a774376b37c50eba92a76a02b1389bd6df67f4..88599c3fa297337b6a3f598b31f92d6e6b4b0993 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -801,7 +801,7 @@ static int parse_stream_command(const char *txt, const char **cmd)
                return -E_MISSING_COLON;
        *cmd = p + 1;
        len = p - txt;
-       re = malloc(len + 1);
+       re = para_malloc(len + 1);
        strncpy(re, txt, len);
        re[len] = '\0';
        ret = get_matching_audio_format_nums(re);
index 8a3175133e69aa57eff7da5155341cbf05532d03..f0d2002d13c28b31c17f7130a4f3c34fc858bd58 100644 (file)
@@ -270,8 +270,8 @@ struct btr_node *btr_new_node(struct btr_node_description *bnd)
        btrn->context = bnd->context;
        btrn->start.tv_sec = 0;
        btrn->start.tv_usec = 0;
-       INIT_LIST_HEAD(&btrn->children);
-       INIT_LIST_HEAD(&btrn->input_queue);
+       init_list_head(&btrn->children);
+       init_list_head(&btrn->input_queue);
        if (!bnd->child) {
                if (bnd->parent) {
                        list_add_tail(&btrn->node, &bnd->parent->children);
index 08f57e9d1ecf9bae1cadead0757fe29418c446c3..cf74cc336de25caa593b198bcfd79a3166996381 100644 (file)
@@ -131,7 +131,7 @@ int cq_get(struct queued_chunk *qc, const char **buf, size_t *num_bytes)
 struct chunk_queue *cq_new(size_t max_pending)
 {
        struct chunk_queue *cq = para_malloc(sizeof(*cq));
-       INIT_LIST_HEAD(&cq->q);
+       init_list_head(&cq->q);
        cq->max_pending = max_pending;
        cq->num_pending = 0;
        return cq;
index f72719f27df46b012165a9e8c8bde3586d602a95..3edaab5dbbf2ec6f086a9483500e431069770b28 100644 (file)
--- a/client.c
+++ b/client.c
@@ -100,7 +100,7 @@ static int create_merged_lpr(const char *line)
        /*
         * The original lpr for the interactive session has no non-option
         * arguments. We create a fresh lpr from the words in "line" and merge
-        * it with the orignal lpr.
+        * it with the original lpr.
         */
        ret = lls(lls_parse(argc, argv, cmd, &argv_lpr, &errctx));
        free_argv(argv);
index dc24a6280acc068bd2cb7cbc0fb178bd8586ca54..c25da96b169126ab36f5b6e7f95a2161d19a3aa9 100644 (file)
@@ -50,13 +50,12 @@ void client_close(struct client_task *ct)
 }
 
 /*
- * The preselect hook for server commands.
+ * This function asks the scheduler to monitor a file descriptor which
+ * corresponds to an active connection. The descriptor is monitored for either
+ * reading or writing, depending on the state of the connection.
  *
- * The task pointer must contain a pointer to the initialized client data
- * structure as it is returned by client_open().
- *
- * This function checks the state of the connection and adds the file descriptor
- * of the connection to the read or write fd set of s accordingly.
+ * The context pointer is assumed to refer to a client task structure that was
+ * initialized earlier by client_open().
  */
 static void client_pre_select(struct sched *s, void *context)
 {
@@ -260,12 +259,15 @@ static int send_sb_command(struct client_task *ct)
 }
 
 /*
- * The post select hook for client commands.
+ * This function reads or writes to the socket file descriptor which
+ * corresponds to an established connection between the client and the server.
+ * It depends on the current state of the connection and on the readiness of
+ * the socket file descriptor which type of I/O is going to be performed.
+ * Besides the initial handshake and authentication, the function sends the
+ * server command and receives the output from the server, if any.
  *
- * Depending on the current state of the connection and the status of the read
- * and write fd sets of s, this function performs the necessary steps to
- * authenticate the connection, to send the command given by t->private_data
- * and to receive para_server's output, if any.
+ * The context pointer refers to a client task structure that was initialized
+ * earlier by client_open().
  */
 static int client_post_select(struct sched *s, void *context)
 {
index 28c5eabb1ae9a4821b60b638be559e837dc54f36..7b464d09cab0ed446aac327fbba6d32f9aadd7b3 100644 (file)
@@ -34,7 +34,7 @@ void add_close_on_fork_list(int fd)
        struct close_on_fork *cof = para_malloc(sizeof(struct close_on_fork));
 
        if (!initialized) {
-               INIT_LIST_HEAD(&close_on_fork_list);
+               init_list_head(&close_on_fork_list);
                initialized = 1;
        }
        cof->fd = fd;
index 8ea725de7898ef817a62c0ba2755c73a0f744572..7b3d6faf90849a92ecbafb98538f277cfef5b02a 100644 (file)
--- a/command.c
+++ b/command.c
@@ -554,7 +554,7 @@ out:
 }
 EXPORT_SERVER_CMD_HANDLER(stat);
 
-const char *aux_info_cb(unsigned cmd_num, bool verbose)
+static const char *aux_info_cb(unsigned cmd_num, bool verbose)
 {
        static char result[80];
        unsigned perms = server_command_perms[cmd_num];
@@ -717,8 +717,7 @@ EXPORT_SERVER_CMD_HANDLER(ff);
 
 static int com_jmp(struct command_context *cc, struct lls_parse_result *lpr)
 {
-       long unsigned int i;
-       int ret;
+       int i, ret;
        char *errctx;
 
        ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx));
@@ -726,18 +725,16 @@ static int com_jmp(struct command_context *cc, struct lls_parse_result *lpr)
                send_errctx(cc, errctx);
                return ret;
        }
-       if (sscanf(lls_input(0, lpr), "%lu", &i) <= 0)
+       if (sscanf(lls_input(0, lpr), "%d", &i) <= 0)
+               return -ERRNO_TO_PARA_ERROR(EINVAL);
+       if (i < 0 || i > 100)
                return -ERRNO_TO_PARA_ERROR(EINVAL);
        mutex_lock(mmd_mutex);
        ret = -E_NO_AUDIO_FILE;
        if (!mmd->afd.afhi.chunks_total)
                goto out;
-       if (i > 100)
-               i = 100;
-       PARA_INFO_LOG("jumping to %lu%%\n", i);
+       PARA_INFO_LOG("jumping to %d%%\n", i);
        mmd->repos_request = (mmd->afd.afhi.chunks_total * i + 50) / 100;
-       PARA_INFO_LOG("sent: %lu, offset before jmp: %li\n",
-               mmd->chunks_sent, mmd->offset);
        mmd->new_vss_status_flags |= VSS_REPOS;
        mmd->new_vss_status_flags &= ~VSS_NEXT;
        ret = 1;
index 15bed6dfa33c896421ab17a89ec426669cf4b025..ff4ce6fb7663c5a0c35e1a42b433060b3b162b89 100644 (file)
@@ -79,7 +79,7 @@ next_buffer:
                sample *= pcd->current_gain;
                sample >>= inertia + 1;
                if (sample > 32767) { /* clip */
-                       PARA_WARNING_LOG("clip: %d\n", sample);
+                       PARA_NOTICE_LOG("clip: %d\n", sample);
                        sample = 32767;
                        pcd->current_gain = (3 * pcd->current_gain +
                                (1 << inertia)) / 4;
diff --git a/error.h b/error.h
index fe44ff5c50487744881ea1d21d1007528a2ecd70..c1e7b9735a0ecc09d959814618eb96345eaa490d 100644 (file)
--- a/error.h
+++ b/error.h
        PARA_ERROR(OGGDEC_VERSION, "vorbis version mismatch"), \
        PARA_ERROR(OGG_EMPTY, "no ogg pages found"), \
        PARA_ERROR(OGG_PACKET_IN, "ogg_stream_packetin() failed"), \
-       PARA_ERROR(OGG_STREAM_FLUSH, "ogg_stream_flush() failed"), \
        PARA_ERROR(OGG_SYNC, "internal ogg storage overflow"), \
        PARA_ERROR(OPENSSH_PARSE, "could not parse openssh private key"), \
        PARA_ERROR(OPUS_COMMENT, "invalid or corrupted opus comment"), \
index a8197308e8323c8fe78546117cc2e9479df0fbfd..8c4545b476e8f792ea7bba6f88b4e83fb952e540 100644 (file)
@@ -45,7 +45,7 @@ static struct i9e_private i9e_private, *i9ep = &i9e_private;
  * running.
  *
  * \return A negative return value of zero means the i9e task terminated. Only
- * in this case it is safe to call ie9_close().
+ * in this case it is safe to call i9e_close().
  */
 int i9e_get_error(void)
 {
@@ -556,7 +556,7 @@ __printf_2_3 void i9e_log(int ll, const char* fmt,...)
  * the given text. If the length of this text exceeds the width of the
  * terminal, the text is shortened by leaving out a part in the middle.
  */
-void ie9_print_status_bar(char *buf, unsigned len)
+void i9e_print_status_bar(char *buf, unsigned len)
 {
        size_t x = i9ep->num_columns, y = (x - 4) / 2;
 
index 40ff294018b221708dd0d1db9cac23c80fb70533..ddf02d76d2bc44a71133844fa0dddf4d9db03778 100644 (file)
@@ -80,7 +80,7 @@ struct i9e_client_info {
 
 int i9e_open(struct i9e_client_info *ici, struct sched *s);
 void i9e_attach_to_stdout(struct btr_node *producer);
-void ie9_print_status_bar(char *buf, unsigned len);
+void i9e_print_status_bar(char *buf, unsigned len);
 void i9e_close(void);
 void i9e_signal_dispatch(int sig_num);
 __printf_2_3 void i9e_log(int ll, const char* fmt,...);
diff --git a/list.h b/list.h
index 66c6d91525031261ff94cd3028e672cb340c06cd..78c302fa322fe6bc2dae2926e95e58189c10c944 100644 (file)
--- a/list.h
+++ b/list.h
  * Copied from the Linux kernel source tree, version 2.6.13.
  *
  * Licensed under the GPL v2 as per the whole kernel source tree.
- *
  */
 
-/** \file list.h doubly linked list implementation */
+/** \file list.h Doubly linked list implementation. */
 
 #include <stddef.h> /* offsetof */
 
-/** get the struct this entry is embedded in */
+/** Get the struct this entry is embedded in. */
 #define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})
 
-/**
- * Non-NULL pointers that will result in page faults under normal
- * circumstances, used to verify that nobody uses non-initialized list entries.
- * Used for poisoning the \a next pointer of struct list_head.
- */
-#define LIST_POISON1  ((void *) 0x00100100)
-/** Non-null pointer, used for poisoning the \a prev pointer of struct
- * list_head
- */
-#define LIST_POISON2  ((void *) 0x00200200)
-
-/** Simple doubly linked list implementation. */
+/** A list head is just a pair of pointers. */
 struct list_head {
-       /** pointer to the next list entry */
+       /** Pointer to the next list entry. */
        struct list_head *next;
-       /** pointer to the previous list entry */
+       /** Pointer to the previous list entry. */
        struct list_head *prev;
 };
 
 /** Define an initialized list head. */
-#define INITIALIZED_LIST_HEAD(name) struct list_head name = { &(name), &(name) }
-
-
-/** must be called before using any other list functions */
-#define INIT_LIST_HEAD(ptr) do { \
-       (ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
+#define INITIALIZED_LIST_HEAD(name) struct list_head name = {&(name), &(name)}
 
-
-/*
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
-                             struct list_head *prev,
-                             struct list_head *next)
+/** This must be called before using any other list functions. */
+static inline void init_list_head(struct list_head *head)
 {
-       next->prev = new;
-       new->next = next;
-       new->prev = prev;
-       prev->next = new;
+       head->next = head;
+       head->prev = head;
 }
 
 /**
- * add a new entry
+ * Insert a new entry after the specified head.
  *
- * \param new new entry to be added
- * \param head list head to add it after
+ * \param entry The new entry to add.
+ * \param head The list head to add it after.
  *
- * Insert a new entry after the specified head.
  * This is good for implementing stacks.
  */
-static inline void para_list_add(struct list_head *new, struct list_head *head)
+static inline void para_list_add(struct list_head *entry, struct list_head *head)
 {
-       __list_add(new, head, head->next);
+       entry->prev = head;
+       entry->next = head->next;
+       head->next->prev = entry;
+       head->next = entry;
 }
 
 /**
- * add a new entry
+ * Insert a new entry before the specified head.
  *
- * \param new new entry to be added
- * \param head list head to add it before
+ * \param entry The new entry to add.
+ * \param head list head to add it before.
  *
- * Insert a new entry before the specified head.
  * This is useful for implementing queues.
  */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
+static inline void list_add_tail(struct list_head *entry, struct list_head *head)
 {
-       __list_add(new, head->prev, head);
+       entry->prev = head->prev;
+       entry->next = head;
+       head->prev->next = entry;
+       head->prev = entry;
 }
 
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
+/**
+ * Delete an entry from a list.
+ *
+ * \param entry The element to delete.
  *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
+ * The list entry is in an undefined state after this and \ref list_empty()
+ * does not return true.
  */
-static inline void __list_del(struct list_head * prev, struct list_head * next)
+static inline void list_del(struct list_head *entry)
 {
-       next->prev = prev;
-       prev->next = next;
+       entry->prev->next = entry->next;
+       entry->next->prev = entry->prev;
+       /*
+        * These non-NULL pointers result in page faults when dereferenced.
+        * This helps to catch bugs resulting from using deleted list heads.
+        */
+       entry->next = (void *)0x00100100;
+       entry->prev = (void *)0x00200200;
 }
 
 /**
- * Delete entry from list.
- *
- * \param entry the element to delete from the list.
+ * Delete an entry from one list and add it as another list's head.
  *
- * Note: list_empty on entry does not return true after this, the entry is
- * in an undefined state.
+ * \param entry The entry to move.
+ * \param head The head that will precede our entry.
  */
-static inline void list_del(struct list_head *entry)
+static inline void list_move(struct list_head *entry, struct list_head *head)
 {
-       __list_del(entry->prev, entry->next);
-       entry->next = LIST_POISON1;
-       entry->prev = LIST_POISON2;
+        list_del(entry);
+        para_list_add(entry, head);
 }
 
 /**
- * delete from one list and add as another's head
+ * Test whether a list contains no entries.
  *
- * \param list: the entry to move
- * \param head: the head that will precede our entry
+ * \param head The list to test.
  */
-static inline void list_move(struct list_head *list, struct list_head *head)
+static inline int list_empty(const struct list_head *head)
 {
-        __list_del(list->prev, list->next);
-        para_list_add(list, head);
+       return head->next == head;
 }
 
 /**
- * test whether a list is empty
+ * Test whether a list has just one entry.
  *
- * \param head the list to test.
+ * \param head The list to test.
  */
-static inline int list_empty(const struct list_head *head)
+static inline int list_is_singular(const struct list_head *head)
 {
-       return head->next == head;
+       return !list_empty(head) && (head->next == head->prev);
 }
 
 /**
- * get the struct for this entry
+ * Get the struct in which this entry is embedded in.
  *
- * \param ptr the &struct list_head pointer.
- * \param type the type of the struct this is embedded in.
- * \param member the name of the list_struct within the struct.
+ * \param ptr The list head pointer.
+ * \param type The type of containing structure.
+ * \param member The name of the list head member within the structure.
  */
-#define list_entry(ptr, type, member) \
-       container_of(ptr, type, member)
+#define list_entry(ptr, type, member) container_of(ptr, type, member)
 
 /**
- * iterate over list of given type
+ * Iterate over a list.
  *
- * \param pos the type * to use as a loop counter.
- * \param head the head for your list.
- * \param member the name of the list_struct within the struct.
+ * \param pos A struct pointer which serves as the iterator.
+ * \param head The head of the list.
+ * \param member The name of the list head member within the structure.
  */
 #define list_for_each_entry(pos, head, member)                         \
        for (pos = list_entry((head)->next, typeof(*pos), member);      \
@@ -169,49 +137,27 @@ static inline int list_empty(const struct list_head *head)
             pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
- * iterate over list of given type safe against removal of list entry
+ * Iterate over list, safe against removal of list entry.
  *
- * \param pos the type * to use as a loop counter.
- * \param n another type * to use as temporary storage
- * \param head the head for your list.
- * \param member the name of the list_struct within the struct.
+ * \param pos The iterator struct pointer.
+ * \param n A second struct pointer which is used as temporary storage.
+ * \param head The head of the list.
+ * \param member The name of the list head member within the structure.
  */
 #define list_for_each_entry_safe(pos, n, head, member)                 \
        for (pos = list_entry((head)->next, typeof(*pos), member),      \
                n = list_entry(pos->member.next, typeof(*pos), member); \
             &pos->member != (head);                                    \
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
-/**
- * iterate backwards over list of given type safe against removal of list entry
- * \param pos the type * to use as a loop counter.
- * \param n another type * to use as temporary storage
- * \param head the head for your list.
- * \param member the name of the list_struct within the struct.
- */
-#define list_for_each_entry_safe_reverse(pos, n, head, member)         \
-       for (pos = list_entry((head)->prev, typeof(*pos), member),      \
-               n = list_entry(pos->member.prev, typeof(*pos), member); \
-            &pos->member != (head);                                    \
-            pos = n, n = list_entry(n->member.prev, typeof(*n), member))
 
 /**
- * Get the first element from a list
- * \param ptr the list head to take the element from.
+ * Get the first element of a list.
+ *
+ * \param ptr The list head to take the element from.
  * \param type The type of the struct this is embedded in.
  * \param member The name of the list_struct within the struct.
  *
- * Note that list is expected to be not empty.
+ * Note that the list is expected to be non-empty.
  */
 #define list_first_entry(ptr, type, member) \
-        list_entry((ptr)->next, type, member)
-
-/**
- * Test whether a list has just one entry.
- *
- * \param head The list to test.
- */
-static inline int list_is_singular(const struct list_head *head)
-{
-       return !list_empty(head) && (head->next == head->prev);
-}
-
+       list_entry((ptr)->next, type, member)
diff --git a/mood.c b/mood.c
index a5d2b025c479bf7907a80e4df22a83fc06791d8e..bf3f39fa26934fd832b5847f034fdd151602145b 100644 (file)
--- a/mood.c
+++ b/mood.c
@@ -269,9 +269,9 @@ static struct mood *alloc_new_mood(const char *name)
        struct mood *m = para_calloc(sizeof(struct mood));
        if (name)
                m->name = para_strdup(name);
-       INIT_LIST_HEAD(&m->accept_list);
-       INIT_LIST_HEAD(&m->deny_list);
-       INIT_LIST_HEAD(&m->score_list);
+       init_list_head(&m->accept_list);
+       init_list_head(&m->deny_list);
+       init_list_head(&m->score_list);
        return m;
 }
 
diff --git a/net.c b/net.c
index 91200fc040bcfebafccf9e737fb65514af9ff8f2..e1951e5e8d87501b1ef9096d3f3df64117e904f0 100644 (file)
--- a/net.c
+++ b/net.c
@@ -288,7 +288,7 @@ struct flowopts *flowopt_new(void)
 {
        struct flowopts *new = para_malloc(sizeof(*new));
 
-       INIT_LIST_HEAD(&new->sockopts);
+       init_list_head(&new->sockopts);
        return new;
 }
 
index 311a514dc86ff6bfb01abf53d16a75672827af12..0565167c256a43bfe86a6442f195a320e1458db8 100644 (file)
@@ -199,9 +199,15 @@ static int oss_post_select(__a_unused struct sched *s, void *context)
 
                if (sound_device_is_busy())
                        return 0;
-               get_btr_sample_rate(btrn, &rate);
-               get_btr_channels(btrn, &ch);
-               get_btr_sample_format(btrn, &format);
+               ret = get_btr_sample_rate(btrn, &rate);
+               if (ret < 0)
+                       goto out;
+               ret = get_btr_channels(btrn, &ch);
+               if (ret < 0)
+                       goto out;
+               ret = get_btr_sample_format(btrn, &format);
+               if (ret < 0)
+                       goto out;
                ret = oss_init(wn, rate, ch, format);
                if (ret < 0)
                        goto out;
diff --git a/play.c b/play.c
index 2346c6b0101045d51e87b5d40abb5b983df6f014..14fac42fd7b6e92566815d4c56b1f4b6b23c88e2 100644 (file)
--- a/play.c
+++ b/play.c
@@ -109,10 +109,6 @@ typedef int (*play_cmd_handler_t)(struct lls_parse_result *lpr);
 struct play_command_info {
        play_cmd_handler_t handler;
 };
-#define EXPORT_PLAY_CMD_HANDLER(_cmd) \
-       const struct play_command_info lsg_play_cmd_com_ ## _cmd ## _user_data = { \
-               .handler = com_ ## _cmd \
-       };
 
 static int loglevel = LL_WARNING;
 
@@ -713,6 +709,11 @@ static void detach_stdout(void)
        btr_remove_node(&pt->btrn);
 }
 
+#define EXPORT_PLAY_CMD_HANDLER(_cmd) \
+       const struct play_command_info lsg_play_cmd_com_ ## _cmd ## _user_data = { \
+               .handler = com_ ## _cmd \
+       };
+
 static int com_quit(__a_unused struct lls_parse_result *lpr)
 {
        pt->rq = CRT_TERM_RQ;
@@ -1051,9 +1052,16 @@ static void session_open(void)
                history_file = para_strdup(OPT_STRING_VAL(HISTORY_FILE));
        else {
                char *home = para_homedir();
-               history_file = make_message("%s/.paraslash/play.history",
-                       home);
+               char *dot_para = make_message("%s/.paraslash", home);
+
                free(home);
+               ret = para_mkdir(dot_para, 0777);
+               /* warn, but otherwise ignore mkdir error */
+               if (ret < 0 && ret != -ERRNO_TO_PARA_ERROR(EEXIST))
+                       PARA_WARNING_LOG("Can not create %s: %s\n", dot_para,
+                               para_strerror(-ret));
+               history_file = make_message("%s/play.history", dot_para);
+               free(dot_para);
        }
        ici.history_file = history_file;
        ici.loglevel = loglevel;
@@ -1094,7 +1102,7 @@ static void session_update_time_string(char *str, unsigned len)
                if (btr_get_input_queue_size(pt->btrn) > 0)
                        return;
        }
-       ie9_print_status_bar(str, len);
+       i9e_print_status_bar(str, len);
 }
 
 /*
diff --git a/sched.c b/sched.c
index a2903940fdaea1b24d6a49cfc2f54766c136070f..aac8efed1bcf8d897e6aef4d07973f2babc8d4f4 100644 (file)
--- a/sched.c
+++ b/sched.c
@@ -244,7 +244,7 @@ struct task *task_register(struct task_info *info, struct sched *s)
        assert(info->post_select);
 
        if (!s->task_list.next)
-               INIT_LIST_HEAD(&s->task_list);
+               init_list_head(&s->task_list);
 
        t->info = *info;
        t->name = para_strdup(info->name);
index ea494d9a7b23f5ee87186917d11e883631ec9cbc..9debdfca5a40a7ada404e9cf4a034140e2509a6b 100644 (file)
@@ -136,9 +136,9 @@ void init_sender_status(struct sender_status *ss,
        }
        ss->default_port = default_port;
 
-       INIT_LIST_HEAD(&ss->client_list);
+       init_list_head(&ss->client_list);
        /* Initialize an access control list */
-       INIT_LIST_HEAD(&ss->acl);
+       init_list_head(&ss->acl);
        for (i = 0; i < lls_opt_given(acl_opt_result); i++) {
                const char *arg = lls_string_val(i, acl_opt_result);
                char addr[16];
index e0d50f4f8689e1de283ef80f8341504bcf386d33..09087f7a72396bf01e51782dbebc1b9d1a82eb7c 100644 (file)
--- a/server.c
+++ b/server.c
@@ -110,7 +110,7 @@ static struct signal_task *signal_task;
 /** The process id of the audio file selector process. */
 pid_t afs_pid = 0;
 
-/* The the main server process (parent of afs and the command handlers). */
+/* The main server process (parent of afs and the command handlers). */
 static pid_t server_pid;
 
 /**
@@ -298,14 +298,14 @@ static int signal_post_select(struct sched *s, __a_unused void *context)
                        if (pid != afs_pid)
                                continue;
                        PARA_EMERG_LOG("fatal: afs died\n");
-                       kill(0, SIGTERM);
-                       goto cleanup;
+                       goto genocide;
                }
                break;
        /* die on sigint/sigterm. Kill all children too. */
        case SIGINT:
        case SIGTERM:
                PARA_EMERG_LOG("terminating on signal %d\n", signum);
+genocide:
                kill(0, SIGTERM);
                /*
                 * We must wait for all of our children to die. For the afs
@@ -320,7 +320,6 @@ static int signal_post_select(struct sched *s, __a_unused void *context)
                while (wait(NULL) != -1 || errno != ECHILD)
                        ; /* still at least one child alive */
                mutex_lock(mmd_mutex);
-cleanup:
                free(mmd->afd.afhi.chunk_table);
                task_notify_all(s, E_DEADLY_SIGNAL);
                return -E_DEADLY_SIGNAL;
index 10251ae7c10b734bd906a644e0832e29b9e6bd9c..10379a0e83098f392e8653467b826925376eda15 100644 (file)
--- a/string.h
+++ b/string.h
@@ -67,7 +67,7 @@ int for_each_line(unsigned flags, char *buf, size_t size,
 } \
 )
 
-__must_check __malloc void *para_realloc(void *p, size_t size);
+__must_check void *para_realloc(void *p, size_t size);
 __must_check __malloc void *para_malloc(size_t size);
 __must_check __malloc void *para_calloc(size_t size);
 __must_check __malloc char *para_strdup(const char *s);
index 2ca2a657de6a79cb9b9e9ee3be47789e11f48e05..8e9ff2c5de79a6385b6472453f3dec417b9ac5cc 100644 (file)
@@ -103,7 +103,7 @@ static void sync_open(struct filter_node *fn)
        const struct lls_opt_result *r_b;
 
        ctx = fn->private_data = para_calloc(sizeof(*ctx));
-       INIT_LIST_HEAD(&ctx->buddies);
+       init_list_head(&ctx->buddies);
 
        /* create socket to listen for incoming packets */
        ret = makesock(
@@ -365,7 +365,8 @@ success:
        ret = -E_SYNC_COMPLETE; /* success */
        goto out;
 fail:
-       PARA_WARNING_LOG("%s\n", para_strerror(-ret));
+       if (ret != -E_BTR_EOF)
+               PARA_WARNING_LOG("%s\n", para_strerror(-ret));
 out:
        sync_close_buddies(ctx);
        btr_splice_out_node(&fn->btrn);
index 04e2982f86bf125c5b4ce8ab2d6daa9280ea0bce..91550aa8c66836239df07193d46d5d470612767e 100644 (file)
@@ -56,6 +56,8 @@ static void udp_close_target(struct sender_client *sc)
        size_t len;
        struct udp_target *ut = sc->private_data;
 
+       if (process_is_command_handler())
+               return;
        if (ut->sent_fec_eof)
                return;
        PARA_NOTICE_LOG("sending FEC EOF\n");
@@ -392,7 +394,7 @@ static void udp_init_target_list(void)
        struct sender_command_data scd;
        int i;
 
-       INIT_LIST_HEAD(&targets);
+       init_list_head(&targets);
        for (i = 0; i < OPT_GIVEN(UDP_TARGET); i++) {
                const char *arg = lls_string_val(i, OPT_RESULT(UDP_TARGET));
                if (udp_resolve_target(arg, &scd) < 0)
@@ -425,7 +427,7 @@ static char *udp_help(void)
 /* Initialize the list of udp targets. */
 static void udp_send_init(void)
 {
-       INIT_LIST_HEAD(&targets);
+       init_list_head(&targets);
        sender_status = SENDER_off;
        udp_init_target_list();
        if (!OPT_GIVEN(UDP_NO_AUTOSTART))
diff --git a/vss.c b/vss.c
index 9857d92dcd7e0e32721aaca15a86fc27fc061292..9e2e32ca3b3bd7979b3c564ff1959dcbe7560446 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -416,7 +416,8 @@ static int compute_group_size(struct vss_task *vsst, struct fec_group *g,
                g->bytes += len;
                g->num_chunks++;
        }
-       assert(g->num_chunks);
+       if (g->num_chunks == 0)
+               return -E_EOF;
        PARA_DEBUG_LOG("group #%u: %u chunks, %u bytes total\n", g->num,
                g->num_chunks, g->bytes);
        return 1;
@@ -964,6 +965,11 @@ static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
        if (ret < 0)
                goto err;
        vsst->afsss = AFS_SOCKET_READY;
+       if (afs_code == NO_ADMISSIBLE_FILES) {
+               PARA_NOTICE_LOG("no admissible files\n");
+               ret = 0;
+               goto err;
+       }
        ret = -E_NOFD;
        if (afs_code != NEXT_AUDIO_FILE) {
                PARA_ERROR_LOG("afs code: %u, expected: %d\n", afs_code,
@@ -1000,9 +1006,11 @@ static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
        return;
 err:
        free(mmd->afd.afhi.chunk_table);
+       mmd->afd.afhi.chunk_table = NULL;
        if (passed_fd >= 0)
                close(passed_fd);
-       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+       if (ret < 0)
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        mmd->new_vss_status_flags = VSS_NEXT;
 }
 
@@ -1170,7 +1178,7 @@ void vss_init(int afs_socket, struct sched *s)
        vsst->afs_socket = afs_socket;
        ms2tv(announce_time, &vsst->announce_tv);
        PARA_INFO_LOG("announce timeval: %lums\n", tv2ms(&vsst->announce_tv));
-       INIT_LIST_HEAD(&fec_client_list);
+       init_list_head(&fec_client_list);
        FOR_EACH_SENDER(i) {
                PARA_NOTICE_LOG("initializing %s sender\n", senders[i]->name);
                senders[i]->init();
index d6d690a16bd5299a6fdb8d304cfe48fc13dbc6c3..e1587afbfe3bd9a0a9c3c10a2d32657794633dc2 100644 (file)
@@ -23,7 +23,7 @@
        [<a href="para_filter.man.html">para_filter</a>]
        [<a href="para_write.man.html">para_write</a>]
        [<a href="para_gui.man.html">para_gui</a>]
-       [<a href="para_mixer.man.html">para_mixere</a>]
+       [<a href="para_mixer.man.html">para_mixer</a>]
        [<a href="para_play.man.html">para_play</a>]
 </p>
 
index 9ef92b7af654ec06f193ad5dd3941648b82a83b8..b2b1f5fabbcc980cf852c1d5c5c177583ea693f9 100644 (file)
@@ -19,7 +19,7 @@ provided at this point. There are several ways to download the source:
                checkout of any of the four integration branches maint,
                master, next, pu (see the
 
-               <a href="manual.html#Git.branches">Git branches</a>
+               <a href="manual.html#Git-branches">Git branches</a>
 
                section of the manual). All previous releases
                correspond to tagged commits and may be checked out
index c7a60cae4ca31994be7f2ed71f02fa2f7a6f5cba..db28a699bdd05516d17de4bf837cc110f737df7e 100644 (file)
@@ -293,7 +293,7 @@ Requirements
        cd osl && make && sudo make install && sudo ldconfig
        sudo apt-get install autoconf libssl-dev m4 \
               libmad0-dev libid3tag0-dev libasound2-dev libvorbis-dev \
-              libfaad-dev libspeex-dev libFLAC-dev libsamplerate-dev realpath \
+              libfaad-dev libspeex-dev libflac-dev libsamplerate-dev \
               libasound2-dev libao-dev libreadline-dev libncurses-dev \
               libopus-dev
 
diff --git a/write.h b/write.h
index cb0beff812121b338e3749e80f63ad2cb99999db..833cb69a5cb6373bae819d5b7c323e1d567c6104 100644 (file)
--- a/write.h
+++ b/write.h
@@ -66,7 +66,7 @@ const struct writer *writer_get(int wid);
 const char *writer_name(int wid);
 void register_writer_node(struct writer_node *wn, struct btr_node *parent,
                struct sched *s);
-void get_btr_sample_rate(struct btr_node *btrn, int32_t *result);
-void get_btr_channels(struct btr_node *btrn, int32_t *result);
-void get_btr_sample_format(struct btr_node *btrn, int32_t *result);
+int get_btr_sample_rate(struct btr_node *btrn, int32_t *result);
+int get_btr_channels(struct btr_node *btrn, int32_t *result);
+int get_btr_sample_format(struct btr_node *btrn, int32_t *result);
 void print_writer_helps(bool detailed);
index 14cc98a4189a5f74907f8bfcf416f62bcc2515c5..41c3eb23728ab11cde71f837d4c58a1ef6908d24 100644 (file)
@@ -174,24 +174,24 @@ void print_writer_helps(bool detailed)
        }
 }
 
-static void get_btr_value(struct btr_node *btrn, const char *cmd,
+static int get_btr_value(struct btr_node *btrn, const char *cmd,
                int32_t *result)
 {
        char *buf = NULL;
        int ret = btr_exec_up(btrn, cmd, &buf);
 
-       if (ret < 0) {
-               /*
-                * This really should not happen. It means one of our parent
-                * nodes died unexpectedly. Proceed with fingers crossed.
-                */
-               PARA_CRIT_LOG("cmd %s: %s\n", cmd, para_strerror(-ret));
-               *result = 0;
-               return;
-       }
+       *result = 0;
+       /*
+        * Errors may happen when the decoder returns EOF before the writer had
+        * a chance to query the buffer tree for the channel count, sample rate
+        * etc.
+        */
+       if (ret < 0)
+               return ret;
        ret = para_atoi32(buf, result);
        assert(ret >= 0);
        free(buf);
+       return ret;
 }
 
 /**
@@ -200,11 +200,11 @@ static void get_btr_value(struct btr_node *btrn, const char *cmd,
  * \param btrn Where to start the search.
  * \param result Filled in by this function.
  *
- * This function is assumed to succeed and terminates on errors.
+ * \return Standard.
  */
-void get_btr_sample_rate(struct btr_node *btrn, int32_t *result)
+int get_btr_sample_rate(struct btr_node *btrn, int32_t *result)
 {
-       get_btr_value(btrn, "sample_rate", result);
+       return get_btr_value(btrn, "sample_rate", result);
 }
 
 /**
@@ -212,10 +212,12 @@ void get_btr_sample_rate(struct btr_node *btrn, int32_t *result)
  *
  * \param btrn See \ref get_btr_sample_rate.
  * \param result See \ref get_btr_sample_rate.
+ *
+ * \return Standard.
  */
-void get_btr_channels(struct btr_node *btrn, int32_t *result)
+int get_btr_channels(struct btr_node *btrn, int32_t *result)
 {
-       get_btr_value(btrn, "channels", result);
+       return get_btr_value(btrn, "channels", result);
 }
 
 /**
@@ -223,8 +225,10 @@ void get_btr_channels(struct btr_node *btrn, int32_t *result)
  *
  * \param btrn See \ref get_btr_sample_rate.
  * \param result Contains the sample format as an enum sample_format type.
+ *
+ * \return Standard.
  */
-void get_btr_sample_format(struct btr_node *btrn, int32_t *result)
+int get_btr_sample_format(struct btr_node *btrn, int32_t *result)
 {
-       get_btr_value(btrn, "sample_format", result);
+       return get_btr_value(btrn, "sample_format", result);
 }