]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge topic branch t/play into pu
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 17 Mar 2024 11:38:21 +0000 (12:38 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 17 Mar 2024 11:38:21 +0000 (12:38 +0100)
This small series contains a few minor tweaks for para_play. The most
obvious change is that para_play is no longer built on systems which
lack libreadline.

<!--
- para_play is no longer built if libreadline is not installed.
-->

* refs/heads/t/play:
  play: Shut down alsa on input EOF.
  play: Simplify and improve get_key_map_seq().
  play: Remove pointless goto in play_post_monitor().
  Return from filter_setup() so callers can reset the terminal.
  Let para_play depend on libreadline.

# Conflicts:
# configure.ac

Makefile.real
audiod.c
filter.c
filter_common.c
play.c
t/t0005-man.sh
web/manual.md

index 21d5fc03477145f087be31a319838d636d3df2b2..fec328a6adbe8be0e8d2d18ae9d0bc3740a10499 100644 (file)
@@ -37,7 +37,7 @@ test_dir := t
 yy_src_dir := yy
 yy_build_dir := $(build_dir)/yy
 
-executables := recv filter audioc write afh play
+executables := recv filter audioc write afh
 ifneq ($(CRYPTOLIB),)
        ifeq ($(HAVE_OSL),yes)
        executables += server upgrade_db
@@ -225,48 +225,48 @@ ifeq ($(HAVE_FAAD),yes)
        audio_format_handlers += aac
 endif
 
-play_objs := $(addsuffix .o, \
-       play fd sched buffer_tree time string net afh_recv afh_common \
-       wma_afh wma_common mp3_afh recv_common udp_recv http_recv dccp_recv \
-       filter_common fec bitstream imdct wav_filter compress_filter \
-       amp_filter prebuffer_filter fecdec_filter wmadec_filter write_common \
-       file_write version sync_filter lsu \
-)
-ifeq ($(NEED_OGG_OBJECTS),yes)
-       play_objs += ogg_afh_common.o
-endif
-ifeq ($(NEED_VORBIS_OBJECTS),yes)
-       play_objs += oggdec_filter.o ogg_afh.o
-endif
-ifeq ($(NEED_SPEEX_OBJECTS),yes)
-       play_objs += spxdec_filter.o spx_afh.o spx_common.o
-endif
-ifeq ($(NEED_OPUS_OBJECTS),yes)
-       play_objs += opusdec_filter.o opus_afh.o opus_common.o
-endif
-ifeq ($(NEED_FLAC_OBJECTS),yes)
-       play_objs += flacdec_filter.o flac_afh.o
-endif
-ifeq ($(HAVE_FAAD),yes)
-       play_objs += aac_afh.o aacdec_filter.o mp4.o
-endif
-ifeq ($(HAVE_MAD),yes)
-       play_objs += mp3dec_filter.o
-endif
-ifeq ($(HAVE_OSS),yes)
-       play_objs += oss_write.o
-endif
-ifeq ($(HAVE_ALSA),yes)
-       play_objs += alsa_write.o
-endif
-ifeq ($(NEED_AO_OBJECTS),yes)
-       play_objs += ao_write.o
-endif
 ifeq ($(HAVE_READLINE),yes)
-       play_objs += interactive.o
-endif
-ifeq ($(HAVE_SAMPLERATE),yes)
-       play_objs += resample_filter.o check_wav.o
+       executables += play
+       play_objs := $(addsuffix .o, \
+               play fd sched buffer_tree time string net afh_recv afh_common \
+               wma_afh wma_common mp3_afh recv_common udp_recv http_recv dccp_recv \
+               filter_common fec bitstream imdct wav_filter compress_filter \
+               amp_filter prebuffer_filter fecdec_filter wmadec_filter write_common \
+               file_write version sync_filter lsu interactive \
+       )
+       ifeq ($(NEED_OGG_OBJECTS),yes)
+               play_objs += ogg_afh_common.o
+       endif
+       ifeq ($(NEED_VORBIS_OBJECTS),yes)
+               play_objs += oggdec_filter.o ogg_afh.o
+       endif
+       ifeq ($(NEED_SPEEX_OBJECTS),yes)
+               play_objs += spxdec_filter.o spx_afh.o spx_common.o
+       endif
+       ifeq ($(NEED_OPUS_OBJECTS),yes)
+               play_objs += opusdec_filter.o opus_afh.o opus_common.o
+       endif
+       ifeq ($(NEED_FLAC_OBJECTS),yes)
+               play_objs += flacdec_filter.o flac_afh.o
+       endif
+       ifeq ($(HAVE_FAAD),yes)
+               play_objs += aac_afh.o aacdec_filter.o mp4.o
+       endif
+       ifeq ($(HAVE_MAD),yes)
+               play_objs += mp3dec_filter.o
+       endif
+       ifeq ($(HAVE_OSS),yes)
+               play_objs += oss_write.o
+       endif
+       ifeq ($(HAVE_ALSA),yes)
+               play_objs += alsa_write.o
+       endif
+       ifeq ($(NEED_AO_OBJECTS),yes)
+               play_objs += ao_write.o
+       endif
+       ifeq ($(HAVE_SAMPLERATE),yes)
+               play_objs += resample_filter.o check_wav.o
+       endif
 endif
 
 write_objs := $(addsuffix .o, write write_common file_write time fd \
index 0fae454c51708a5db51a2833e1fa5fc74d0b72a2..3e86af537431ff67b00a47694fcaa506dea41837 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -829,11 +829,14 @@ static int parse_stream_command(const char *txt, const char **cmd)
 static int add_filter(int format, const char *cmdline)
 {
        struct audio_format_info *a = &afi[format];
-       int filter_num, nf = a->num_filters;
+       int ret, filter_num, nf = a->num_filters;
        void *cfg;
        struct lls_parse_result *flpr;
 
-       filter_num = filter_setup(cmdline, &cfg, &flpr);
+       ret = filter_setup(cmdline, &cfg, &flpr);
+       if (ret < 0)
+               return ret;
+       filter_num = ret;
        a->filter_lpr = arr_realloc(a->filter_lpr, nf + 1, sizeof(flpr));
        a->filter_conf = arr_realloc(a->filter_conf, nf + 1, sizeof(void *));
        a->filter_nums = arr_realloc(a->filter_nums, nf + 1, sizeof(unsigned));
index 722cb16fb35bfaec09bbaca046ebf62931df8036..50447ec0cd2a165c974e4fea68e288e98a1713e3 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -128,7 +128,10 @@ int main(int argc, char *argv[])
                struct task_info ti;
 
                fn = fns[i] = zalloc(sizeof(*fn));
-               fn->filter_num = filter_setup(fa, &fn->conf, &filter_lpr);
+               ret = filter_setup(fa, &fn->conf, &filter_lpr);
+               if (ret < 0)
+                       goto teardown;
+               fn->filter_num = ret;
                name = filter_name(fn->filter_num);
                fn->lpr = filter_lpr;
                PARA_DEBUG_LOG("filter #%d: %s\n", i, name);
@@ -153,6 +156,7 @@ int main(int argc, char *argv[])
        btr_log_tree(sit->btrn, LL_INFO);
        ret = schedule(&s);
        sched_shutdown(&s);
+teardown:
        for (i--; i >= 0; i--) {
                struct filter_node *fn = fns[i];
 
index f48e457005ca3510fb51d5e5f95405af15d927c1..7966b806f0745bfc6d35b630693ef31e285ac3a8 100644 (file)
@@ -67,11 +67,11 @@ const char *filter_name(int filter_num)
  * filter, optionally followed by options for this filter. If yes, call the
  * command line parser of that filter and its ->setup method.
  *
- * \return This function either succeeds or does not return. On success, the
- * number of the filter is returned and conf is initialized to point to the
- * filter configuration as returned by the filter's ->setup() method, if any.
- * Moreover, *lprp is initialized to contain the parsed command line options.
- * On errors, the function calls exit(EXIT_FAILURE).
+ * \return On success, the number of the filter is returned and conf is
+ * initialized to point to the filter configuration as returned by the filter's
+ * ->setup() method, if any.  Moreover, *lprp is initialized to contain the
+ * parsed command line options. On errors a negative paraslash error code is
+ * returned.
  */
 int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp)
 {
@@ -80,9 +80,10 @@ int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp)
        const struct lls_command *cmd;
        const struct filter *f;
 
+       *lprp = NULL;
        ret = create_argv(fa, " \t\n", &argv);
        if (ret < 0)
-               goto fail;
+               return ret;
        argc = ret;
        ret = lls(lls_lookup_subcmd(argv[0], filter_cmd_suite, &errctx));
        if (ret < 0)
@@ -105,12 +106,10 @@ free_argv:
        free_argv(argv);
        if (ret >= 0)
                return ret;
-fail:
        if (errctx)
                PARA_ERROR_LOG("%s\n", errctx);
        free(errctx);
-       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
-       exit(EXIT_FAILURE);
+       return ret;
 }
 
 /**
diff --git a/play.c b/play.c
index bd183b6b8dd48906e08cf142d7ff8c1e05aad48a..c9a9f7d7e8a69a0d2db51d3fdbdc8e04aec1c6d7 100644 (file)
--- a/play.c
+++ b/play.c
@@ -24,6 +24,7 @@
 #include "recv.h"
 #include "write.h"
 #include "fd.h"
+#include "interactive.h"
 
 /** Array of error strings. */
 DEFINE_PARA_ERRLIST;
@@ -222,7 +223,7 @@ static int get_playback_error(void)
        int err;
 
        if (!pt->wn.task)
-               return 0;
+               return 1;
        err = task_status(pt->wn.task);
        if (err >= 0)
                return 0;
@@ -253,7 +254,7 @@ static int eof_cleanup(void)
 
        decoder = filter_get(pt->fn.filter_num);
        task_reap(&pt->fn.task);
-       if (decoder->close)
+       if (decoder && decoder->close)
                decoder->close(&pt->fn);
        btr_remove_node(&pt->fn.btrn);
        lls_free_parse_result(pt->fn.lpr, FILTER_CMD(pt->fn.filter_num));
@@ -470,8 +471,6 @@ static void kill_stream(void)
                task_notify(pt->wn.task, E_EOF);
 }
 
-#ifdef HAVE_READLINE
-
 /* only called from com_prev(), nec. only if we have readline */
 static int previous_valid_file(void)
 {
@@ -488,8 +487,6 @@ static int previous_valid_file(void)
        return -E_NO_VALID_FILES;
 }
 
-#include "interactive.h"
-
 /*
  * Define the default (internal) key mappings and helper functions to get the
  * key sequence or the command from a key id, which is what we obtain from
@@ -573,15 +570,17 @@ static inline char *get_internal_key_map_seq(int key)
        return para_strdup(default_keyseqs[get_internal_key_map_idx(key)]);
 }
 
-static char *get_user_key_map_seq(int key)
+static char *get_key_map_seq(int key)
 {
-       const char *kma = get_user_key_map_arg(key);
-       const char *p = strchr(kma + 1, ':');
+       const char *kma, *p;
        char *result;
        int len;
 
-       if (!p)
-               return NULL;
+       if (is_internal_key(key))
+               return get_internal_key_map_seq(key);
+       kma = get_user_key_map_arg(key);
+       p = strchr(kma + 1, ':');
+       assert(p); /* We checked earlier that kma contains a colon */
        len = p - kma;
        result = alloc(len + 1);
        memcpy(result, kma, len);
@@ -589,12 +588,6 @@ static char *get_user_key_map_seq(int key)
        return result;
 }
 
-static char *get_key_map_seq(int key)
-{
-       return is_internal_key(key)?
-               get_internal_key_map_seq(key) : get_user_key_map_seq(key);
-}
-
 static char *get_key_map_seq_safe(int key)
 {
        const char hex[] = "0123456789abcdef";
@@ -1098,64 +1091,6 @@ static void session_update_time_string(char *str, unsigned len)
        i9e_print_status_bar(str, len);
 }
 
-/*
- * If we are about to die we must call i9e_close() to reset the terminal.
- * However, i9e_close() must be called in *this* context, i.e. from
- * play_task.post_monitor() rather than from i9e_post_monitor(), because
- * otherwise i9e would access freed memory upon return. So the play task must
- * stay alive until the i9e task terminates.
- *
- * We achieve this by sending a fake SIGTERM signal via i9e_signal_dispatch()
- * and reschedule. In the next iteration, i9e->post_monitor returns an error and
- * terminates. Subsequent calls to i9e_get_error() then return negative and we
- * are allowed to call i9e_close() and terminate as well.
- */
-static int session_post_monitor(__a_unused struct sched *s)
-{
-       int ret;
-
-       if (pt->background)
-               detach_stdout();
-       else
-               attach_stdout(__FUNCTION__);
-       ret = i9e_get_error();
-       if (ret < 0) {
-               kill_stream();
-               i9e_close();
-               para_log = stderr_log;
-               free(ici.history_file);
-               return ret;
-       }
-       if (get_playback_state() == 'X')
-               i9e_signal_dispatch(SIGTERM);
-       return 0;
-}
-
-#else /* HAVE_READLINE */
-
-static int session_post_monitor(struct sched *s)
-{
-       char c;
-
-       if (!sched_read_ok(STDIN_FILENO, s))
-               return 0;
-       if (read(STDIN_FILENO, &c, 1))
-               do_nothing;
-       kill_stream();
-       return 1;
-}
-
-static void session_open(void)
-{
-}
-
-static void session_update_time_string(char *str, __a_unused unsigned len)
-{
-       printf("\r%s     ", str);
-       fflush(stdout);
-}
-#endif /* HAVE_READLINE */
-
 static void play_pre_monitor(struct sched *s, __a_unused void *context)
 {
        char state;
@@ -1194,18 +1129,24 @@ static unsigned get_time_string(char **result)
        );
 }
 
-static int play_post_monitor(struct sched *s, __a_unused void *context)
+static int play_post_monitor(__a_unused struct sched *s, __a_unused void *context)
 {
-       int ret;
+       int ret, i9e_error;
 
+       if (pt->background)
+               detach_stdout();
+       else
+               attach_stdout(__FUNCTION__);
+       i9e_error = i9e_get_error();
        ret = eof_cleanup();
-       if (ret < 0) {
-               pt->rq = CRT_TERM_RQ;
-               return 0;
-       }
-       ret = session_post_monitor(s);
-       if (ret < 0)
-               goto out;
+       if (pt->rq == CRT_TERM_RQ || i9e_error < 0) /* com_quit() or CTRL+D */
+               kill_stream(); /* terminate receiver/filter/writer */
+       if ((ret < 0 || pt->rq == CRT_TERM_RQ) && i9e_error >= 0)
+               i9e_signal_dispatch(SIGTERM); /* terminate the i9e task */
+       if (ret < 0) /* unexpected error from the writer node */
+               return ret;
+       if (ret != 0 && i9e_error < 0) /* eof, and i9e has died */
+               return i9e_error;
        if (!pt->wn.btrn && !pt->fn.btrn) {
                char state = get_playback_state();
                if (state == 'P' || state == 'R' || state == 'F') {
@@ -1214,8 +1155,7 @@ static int play_post_monitor(struct sched *s, __a_unused void *context)
                        if (ret < 0) {
                                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                                pt->rq = CRT_TERM_RQ;
-                               ret = 1;
-                               goto out;
+                               return 1;
                        }
                        pt->next_update = *now;
                }
@@ -1229,9 +1169,7 @@ static int play_post_monitor(struct sched *s, __a_unused void *context)
                free(str);
                tv_add(now, &delay, &pt->next_update);
        }
-       ret = 1;
-out:
-       return ret;
+       return 1;
 }
 
 /**
@@ -1278,6 +1216,10 @@ int main(int argc, char *argv[])
        }, &sched);
        ret = schedule(&sched);
        sched_shutdown(&sched);
+       i9e_close();
+       wipe_receiver_node();
+       para_log = stderr_log;
+       free(ici.history_file);
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
index ee1949c05a04d4fd4b81f2b9c847a403a753e2f5..307be1240a559dd5b8a1773a0b1dc1c2447e1a4f 100755 (executable)
@@ -58,7 +58,12 @@ else
                "grep_man '$regex' server"
 fi
 
-# para_play is always built
-regex='LIST OF COMMANDS.\{100,\}'
-test_expect_success 'para_play: play commands' "grep_man '$regex' play"
+test_require_objects 'play'
+missing_objects="$result"
+if [[ -n "$missing_objects" ]]; then
+       test_skip 'para_play' "missing object(s): $missing_objects"
+else
+       regex='LIST OF COMMANDS.\{100,\}'
+       test_expect_success 'para_play: play commands' "grep_man '$regex' play"
+fi
 test_done
index b5329ea07f3d8a2f9553f384c9129c4ad1a262e3..a2942d71ac6d1f63aab3ec8a08ee2cc7c516fe1f 100644 (file)
@@ -385,9 +385,10 @@ the ao writer (ESD, PulseAudio,...).  Debian package: `libao-dev`.
 para_gui. Debian package: `libncurses-dev`.
 
 - [GNU
-Readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html). If
-this library (`libreadline-dev`) is installed, para_client, para_audioc
-and para_play support interactive sessions.
+Readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html). Only if
+this library (`libreadline-dev`) is installed, para_play is built, Without it,
+para_client(1) and para_audioc(1) still work, but lack support for interactive
+sessions.
 
 Installation
 ------------