From d02f88dfc3911262174afe6017e04d70e8557a7a Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Tue, 26 Jun 2012 01:48:04 +0200 Subject: [PATCH] para_play, infrastructure. Now that the preparatory changes to the interactive subsystem (single key mode, status bar, signal handling) and the writer nodes (notifications) and receiver nodes (btr exec mechanism) are in place, we can move on to the para_play executable. This patch adds only the necessary changes to the build system and provides a dummy implementation of para_play. The real implementation will be provided as as a separate patch in the next commit. --- Makefile.in | 11 ++++- configure.ac | 68 ++++++++++++++++++++++--- error.h | 4 ++ m4/gengetopt/makefile | 1 + m4/gengetopt/play.m4 | 11 +++++ play.c | 112 ++++++++++++++++++++++++++++++++++++++++++ play.cmd | 8 +++ server.c | 2 +- web/manual.m4 | 6 ++- 9 files changed, 213 insertions(+), 10 deletions(-) create mode 100644 m4/gengetopt/play.m4 create mode 100644 play.c create mode 100644 play.cmd diff --git a/Makefile.in b/Makefile.in index 3755e591..4d1c2323 100644 --- a/Makefile.in +++ b/Makefile.in @@ -141,6 +141,10 @@ $(man_dir)/para_audiod.1: para_audiod audiod_command_list.man | $(man_dir) @[ -z "$(Q)" ] || echo 'MAN $<' $(Q) $(HELP2MAN) -h --detailed-help -N -i audiod_command_list.man ./para_audiod > $@ +$(man_dir)/para_play.1: para_play play_command_list.man | $(man_dir) + @[ -z "$(Q)" ] || echo 'MAN $<' + $(Q) $(HELP2MAN) -h --detailed-help -N -i play_command_list.man ./para_play > $@ + $(man_dir)/%.1: % | $(man_dir) @[ -z "$(Q)" ] || echo 'MAN $<' $(Q) $(HELP2MAN) -h --detailed-help -N ./$< > $@ @@ -219,7 +223,7 @@ $(dep_dir)/%.d: %.c | $(dep_dir) all_objs := @recv_objs@ @filter_objs@ @client_objs@ @gui_objs@ \ @audiod_objs@ @audioc_objs@ @fade_objs@ @server_objs@ \ - @write_objs@ @afh_objs@ + @write_objs@ @afh_objs@ @play_objs@ deps := $(addprefix $(dep_dir)/, $(all_objs:.o=.d)) recv_objs := $(addprefix $(object_dir)/, @recv_objs@) @@ -232,6 +236,7 @@ fade_objs := $(addprefix $(object_dir)/, @fade_objs@) server_objs := $(addprefix $(object_dir)/, @server_objs@) write_objs := $(addprefix $(object_dir)/, @write_objs@) afh_objs := $(addprefix $(object_dir)/, @afh_objs@) +play_objs := $(addprefix $(object_dir)/, @play_objs@) ifeq ($(findstring clean, $(MAKECMDGOALS)),) -include $(deps) @@ -277,6 +282,10 @@ para_afh: $(afh_objs) @[ -z "$(Q)" ] || echo 'LD $@' $(Q) $(CC) $(LDFLAGS) -o $@ $(afh_objs) @afh_ldflags@ +para_play: $(play_objs) + @[ -z "$(Q)" ] || echo 'LD $@' + $(Q) $(CC) $(LDFLAGS) -o $@ $(play_objs) @play_ldflags@ + clean: @[ -z "$(Q)" ] || echo 'CLEAN' $(Q) rm -f @executables@ diff --git a/configure.ac b/configure.ac index 2df73396..661081cf 100644 --- a/configure.ac +++ b/configure.ac @@ -102,8 +102,9 @@ all_errlist_objs="mp3_afh afh_common net string signal time daemon exec send_common ggo udp_recv color fec fecdec_filter prebuffer_filter bitstream imdct wma_afh wma_common wmadec_filter buffer_tree crypt_common - gui gui_theme sideband afh_recv" -executables="recv filter audioc write client afh audiod" + gui gui_theme sideband afh_recv play" + +executables="recv filter audioc write client afh audiod play" recv_cmdline_objs="add_cmdline(recv http_recv dccp_recv udp_recv afh_recv)" @@ -154,6 +155,17 @@ client_ldflags="" gui_cmdline_objs="add_cmdline(gui)" gui_errlist_objs="exec signal string stat ringbuffer fd gui gui_theme" gui_objs="$gui_cmdline_objs $gui_errlist_objs" +play_errlist_objs="play fd sched ggo 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 +" +play_cmdline_objs="add_cmdline(http_recv dccp_recv udp_recv afh_recv compress_filter amp_filter prebuffer_filter file_write play)" +play_ldflags="-lm" ########################################################################### snprintf # =========================================================================== # http://www.nongnu.org/autoconf-archive/ax_func_snprintf.html @@ -514,6 +526,10 @@ if test ${have_core_audio} = yes; then audiod_cmdline_objs="$audiod_cmdline_objs osx_write.cmdline" audiod_ldflags="$audiod_ldflags $f" + play_errlist_objs="$play_errlist_objs osx_write ipc" + play_cmdline_objs="$play_cmdline_objs osx_write.cmdline" + play_ldflags="$play_ldflags $f" + write_errlist_objs="$write_errlist_objs osx_write ipc" write_cmdline_objs="$write_cmdline_objs osx_write.cmdline" write_ldflags="$write_ldflags $f" @@ -592,12 +608,14 @@ if test "$have_vorbis" = "yes" || test "$have_speex" = "yes"; then server_ldflags="$server_ldflags $ogg_libs" filter_ldflags="$filter_ldflags $ogg_libs" audiod_ldflags="$audiod_ldflags $ogg_libs" + play_ldflags="$play_ldflags $ogg_libs" afh_ldflags="$afh_ldflags $ogg_libs" recv_ldflags="$recv_ldflags $ogg_libs" all_errlist_objs="$all_errlist_objs ogg_afh_common" afh_errlist_objs="$afh_errlist_objs ogg_afh_common" recv_errlist_objs="$recv_errlist_objs ogg_afh_common" server_errlist_objs="$server_errlist_objs ogg_afh_common" + play_errlist_objs="$play_errlist_objs ogg_afh_common" fi if test "$have_vorbis" = "yes"; then all_errlist_objs="$all_errlist_objs oggdec_filter ogg_afh" @@ -607,12 +625,14 @@ if test "$have_vorbis" = "yes"; then server_ldflags="$server_ldflags $vorbis_libs" filter_ldflags="$filter_ldflags $vorbis_libs" audiod_ldflags="$audiod_ldflags $vorbis_libs" + play_ldflags="$play_ldflags $vorbis_libs" afh_ldflags="$afh_ldflags $vorbis_libs" recv_ldflags="$recv_ldflags $vorbis_libs" server_errlist_objs="$server_errlist_objs ogg_afh" filter_errlist_objs="$filter_errlist_objs oggdec_filter" audiod_errlist_objs="$audiod_errlist_objs oggdec_filter" + play_errlist_objs="$play_errlist_objs oggdec_filter ogg_afh" afh_errlist_objs="$afh_errlist_objs ogg_afh" recv_errlist_objs="$recv_errlist_objs ogg_afh" @@ -629,12 +649,14 @@ if test "$have_speex" = "yes"; then server_ldflags="$server_ldflags $speex_libs" filter_ldflags="$filter_ldflags $speex_libs" audiod_ldflags="$audiod_ldflags $speex_libs" + play_ldflags="$play_ldflags $speex_libs" afh_ldflags="$afh_ldflags $speex_libs" recv_ldflags="$recv_ldflags $speex_libs" server_errlist_objs="$server_errlist_objs spx_afh spx_common" filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common" audiod_errlist_objs="$audiod_errlist_objs spxdec_filter spx_common" + play_errlist_objs="$play_errlist_objs spxdec_filter spx_afh spx_common" afh_errlist_objs="$afh_errlist_objs spx_afh spx_common" recv_errlist_objs="$recv_errlist_objs spx_afh spx_common" @@ -671,12 +693,14 @@ if test "$have_faad" = "yes"; then filter_errlist_objs="$filter_errlist_objs aacdec_filter aac_common" afh_errlist_objs="$afh_errlist_objs aac_common aac_afh" audiod_errlist_objs="$audiod_errlist_objs aacdec_filter aac_common" + play_errlist_objs="$play_errlist_objs aacdec_filter aac_afh aac_common" server_errlist_objs="$server_errlist_objs aac_afh aac_common" recv_errlist_objs="$recv_errlist_objs aac_afh aac_common" server_ldflags="$server_ldflags $faad_libs -lfaad" filter_ldflags="$filter_ldflags $faad_libs -lfaad" audiod_ldflags="$audiod_ldflags $faad_libs -lfaad" + play_ldflags="$play_ldflags $faad_libs -lfaad" afh_ldflags="$afh_ldflags $faad_libs -lfaad" recv_ldflags="$afh_ldflags $faad_libs -lfaad" @@ -718,11 +742,14 @@ if test "$have_mad" = "yes"; then AC_DEFINE(HAVE_MAD, 1, define to 1 if you want to build the mp3dec filter) filter_cmdline_objs="$filter_cmdline_objs add_cmdline(mp3dec_filter)" audiod_cmdline_objs="$audiod_cmdline_objs add_cmdline(mp3dec_filter)" + play_cmdline_objs="$play_cmdline_objs add_cmdline(mp3dec_filter)" all_errlist_objs="$all_errlist_objs mp3dec_filter" filter_errlist_objs="$filter_errlist_objs mp3dec_filter" audiod_errlist_objs="$audiod_errlist_objs mp3dec_filter" + play_errlist_objs="$play_errlist_objs mp3dec_filter" filter_ldflags="$filter_ldflags $mad_libs -lmad" audiod_ldflags="$audiod_ldflags $mad_libs -lmad" + play_ldflags="$play_ldflags $mad_libs -lmad" audiod_audio_formats="$audiod_audio_formats mp3" filters="$filters mp3dec" AC_SUBST(mad_cppflags) @@ -763,7 +790,9 @@ if test ${have_libid3tag} = yes; then AC_DEFINE(HAVE_LIBID3TAG, 1, define to 1 you have libid3tag) server_ldflags="$server_ldflags $id3tag_libs -lid3tag -lz" afh_ldflags="$afh_ldflags $id3tag_libs -lid3tag -lz" + play_ldflags="$play_ldflags -lz" recv_ldflags="$recv_ldflags $id3tag_libs -lid3tag" + play_ldflags="$play_ldflags $id3tag_libs -lid3tag" AC_SUBST(id3tag_cppflags) else AC_MSG_WARN([no support for id3v2 tags]) @@ -796,11 +825,13 @@ if test "$have_flac" = "yes"; then all_errlist_objs="$all_errlist_objs flacdec_filter flac_afh" filter_errlist_objs="$filter_errlist_objs flacdec_filter" audiod_errlist_objs="$audiod_errlist_objs flacdec_filter" + play_errlist_objs="$play_errlist_objs flacdec_filter flac_afh" afh_errlist_objs="$afh_errlist_objs flac_afh" server_errlist_objs="$server_errlist_objs flac_afh" recv_errlist_objs="$recv_errlist_objs flac_afh" filter_ldflags="$filter_ldflags $flac_libs -lFLAC" audiod_ldflags="$audiod_ldflags $flac_libs -lFLAC" + play_ldflags="$play_ldflags $flac_libs -lFLAC" server_ldflags="$server_ldflags $flac_libs -lFLAC" afh_ldflags="$afh_ldflags $flac_libs -lFLAC" recv_ldflags="$afh_ldflags $flac_libs -lFLAC" @@ -824,7 +855,10 @@ msg="=> will not build oss writer" AC_CHECK_HEADER(sys/soundcard.h, [ audiod_errlist_objs="$audiod_errlist_objs oss_write" + play_errlist_objs="$play_errlist_objs oss_write" audiod_cmdline_objs="$audiod_cmdline_objs add_cmdline(oss_write)" + play_cmdline_objs="$play_cmdline_objs add_cmdline(oss_write)" + write_errlist_objs="$write_errlist_objs oss_write" write_cmdline_objs="$write_cmdline_objs add_cmdline(oss_write)" fade_errlist_objs="$fade_errlist_objs oss_mix" @@ -837,6 +871,7 @@ AC_CHECK_HEADER(sys/soundcard.h, [ AC_CHECK_LIB(ossaudio, _oss_ioctl, [ audiod_ldflags="$audiod_ldflags -lossaudio" + play_ldflags="$play_ldflags -lossaudio" write_ldflags="$write_ldflags -lossaudio" fade_ldflags="$fade_ldflags -lossaudio" ] @@ -880,6 +915,10 @@ if test "$have_alsa" = "yes"; then audiod_errlist_objs="$audiod_errlist_objs alsa_write" audiod_cmdline_objs="$audiod_cmdline_objs add_cmdline(alsa_write)" audiod_ldflags="$audiod_ldflags -lasound" + play_errlist_objs="$play_errlist_objs alsa_write" + play_cmdline_objs="$play_cmdline_objs add_cmdline(alsa_write)" + play_ldflags="$play_ldflags -lasound" + write_errlist_objs="$write_errlist_objs alsa_write" write_cmdline_objs="$write_cmdline_objs add_cmdline(alsa_write)" write_ldflags="$write_ldflags -lasound" @@ -983,6 +1022,10 @@ if test "$have_ao" = "yes"; then audiod_cmdline_objs="$audiod_cmdline_objs add_cmdline(ao_write)" audiod_ldflags="$audiod_ldflags -lao -lpthread" + play_errlist_objs="$play_errlist_objs ao_write" + play_cmdline_objs="$play_cmdline_objs add_cmdline(ao_write)" + play_ldflags="$play_ldflags -lao -lpthread" + write_errlist_objs="$write_errlist_objs ao_write" write_cmdline_objs="$write_cmdline_objs add_cmdline(ao_write)" write_ldflags="$write_ldflags $ao_libs -lao -lpthread" @@ -1020,12 +1063,12 @@ AC_CHECK_HEADERS([readline/readline.h], [ ]) if test "$have_readline" = "yes"; then readline_libs="$readline_libs -lreadline" - AC_SEARCH_LIBS([rl_replace_line], [readline], [], [have_readline="no"]) + AC_SEARCH_LIBS([rl_free_keymap], [readline], [], [have_readline="no"]) if test "$have_readline" = "no"; then # try with -lcurses # clear cache AC_MSG_NOTICE([trying again with -lcurses]) - unset ac_cv_search_rl_replace_line 2> /dev/null - AC_SEARCH_LIBS([rl_replace_line], [readline], [ + unset ac_cv_search_rl_free_keymap 2> /dev/null + AC_SEARCH_LIBS([rl_free_keymap], [readline], [ have_readline=yes readline_libs="$readline_libs -lcurses" ], [], [-lcurses]) @@ -1033,8 +1076,8 @@ if test "$have_readline" = "yes"; then if test "$have_readline" = "no"; then # try with -ltermcap # clear cache AC_MSG_NOTICE([trying again with -ltermcap]) - unset ac_cv_search_rl_replace_line 2> /dev/null - AC_SEARCH_LIBS([rl_replace_line], [readline], [ + unset ac_cv_search_rl_free_keymap 2> /dev/null + AC_SEARCH_LIBS([rl_free_keymap], [readline], [ have_readline=yes readline_libs="$readline_libs -ltermcap" ], [], [-ltermcap]) @@ -1047,6 +1090,8 @@ if test "$have_readline" = "yes"; then client_ldflags="$client_ldflags $readline_libs" audioc_errlist_objs="$audioc_errlist_objs buffer_tree interactive sched time" audioc_ldflags="$audioc_ldflags $readline_libs" + play_errlist_objs="$play_errlist_objs interactive" + play_ldflags="$play_ldflags $readline_libs" AC_SUBST(readline_cppflags) AC_DEFINE(HAVE_READLINE, 1, define to 1 to turn on readline support) else @@ -1106,6 +1151,8 @@ write_objs="$write_cmdline_objs $write_errlist_objs" client_objs="$client_cmdline_objs $client_errlist_objs" audioc_objs="$audioc_cmdline_objs $audioc_errlist_objs" afh_objs="$afh_cmdline_objs $afh_errlist_objs" +play_objs="$play_cmdline_objs $play_errlist_objs" + AC_SUBST(recv_objs, add_dot_o($recv_objs)) AC_SUBST(recv_ldflags, $recv_ldflags) @@ -1151,6 +1198,13 @@ AC_SUBST(gui_objs, add_dot_o($gui_objs)) AC_DEFINE_UNQUOTED(INIT_GUI_ERRLISTS, objlist_to_errlist($gui_errlist_objs), errors used by para_gui) +AC_SUBST(play_objs, add_dot_o($play_objs)) +AC_SUBST(play_ldflags, $play_ldflags) +AC_DEFINE_UNQUOTED(INIT_PLAY_ERRLISTS, + objlist_to_errlist($play_errlist_objs), errors used by para_play) + +AC_MSG_NOTICE(play objs: $play_objs) + enum="$(for i in $filters; do printf "${i}_FILTER, " | tr '[a-z]' '[A-Z]'; done)" AC_DEFINE_UNQUOTED(FILTER_ENUM, $enum NUM_SUPPORTED_FILTERS, enum of supported filters) diff --git a/error.h b/error.h index 8b1ae341..fd2e01a8 100644 --- a/error.h +++ b/error.h @@ -50,6 +50,10 @@ extern const char **para_errlist[]; PARA_ERROR(SB_PACKET_SIZE, "invalid sideband packet size or protocol error"), \ +#define PLAY_ERRORS \ + PARA_ERROR(PLAY_SYNTAX, "play syntax error"), \ + + #define FLACDEC_FILTER_ERRORS \ PARA_ERROR(FLACDEC_DECODER_ALLOC, "could not allocate stream decoder"), \ PARA_ERROR(FLACDEC_DECODER_INIT, "could not init stream decoder"), \ diff --git a/m4/gengetopt/makefile b/m4/gengetopt/makefile index c81eda46..c88dfd98 100644 --- a/m4/gengetopt/makefile +++ b/m4/gengetopt/makefile @@ -34,6 +34,7 @@ $(ggo_dir)/client.ggo: \ $(m4_ggo_dir)/history_file.m4 \ $(m4_ggo_dir)/complete.m4 $(ggo_dir)/fade.ggo: $(m4_ggo_dir)/loglevel.m4 $(m4_ggo_dir)/config_file.m4 +$(ggo_dir)/play.ggo: $(m4_ggo_dir)/loglevel.m4 $(m4_ggo_dir)/config_file.m4 $(ggo_dir)/%.ggo: $(m4_ggo_dir)/%.m4 $(m4_ggo_dir)/header.m4 | $(ggo_dir) @[ -z "$(Q)" ] || echo 'M4 $<' diff --git a/m4/gengetopt/play.m4 b/m4/gengetopt/play.m4 new file mode 100644 index 00000000..9bdc767c --- /dev/null +++ b/m4/gengetopt/play.m4 @@ -0,0 +1,11 @@ +args "--unamed-opts=audio_file --no-handle-version --conf-parser --no-handle-help" +include(header.m4) +define(CURRENT_PROGRAM,para_play) +define(DEFAULT_CONFIG_FILE,~/.paraslash/play.conf) + +######################### +section "General options" +######################### + +include(loglevel.m4) +include(config_file.m4) diff --git a/play.c b/play.c new file mode 100644 index 00000000..fc33f68b --- /dev/null +++ b/play.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/** \file play.c Paraslash's standalone player. */ + +#include + +#include "para.h" +#include "list.h" +#include "play.cmdline.h" +#include "filter.cmdline.h" +#include "error.h" +#include "ggo.h" +#include "buffer_tree.h" +#include "version.h" +#include "string.h" +#include "sched.h" +#include "filter.h" +#include "afh.h" +#include "recv.h" +#include "write.h" +#include "write_common.h" +#include "fd.h" + +static struct play_args_info conf; + +/** Initialize the array of errors for para_play. */ +INIT_PLAY_ERRLISTS; + +/* Activate the afh receiver. */ +extern void afh_recv_init(struct receiver *r); +#undef AFH_RECEIVER +#define AFH_RECEIVER {.name = "afh", .init = afh_recv_init}, +DEFINE_RECEIVER_ARRAY; + +/* FIXME: This is needed by the amp filter. */ +char *stat_item_values[NUM_STAT_ITEMS] = {NULL}; + +static int loglevel = LL_WARNING; +INIT_STDERR_LOGGING(loglevel); + +__noreturn static void print_help_and_die(void) +{ + int d = conf.detailed_help_given; + const char **p = d? play_args_info_detailed_help + : play_args_info_help; + + printf_or_die("%s\n\n", PLAY_CMDLINE_PARSER_PACKAGE "-" + PLAY_CMDLINE_PARSER_VERSION); + printf_or_die("%s\n\n", play_args_info_usage); + for (; *p; p++) + printf_or_die("%s\n", *p); + print_filter_helps(d); + print_writer_helps(d); + exit(0); +} + +static void parse_config_or_die(int argc, char *argv[]) +{ + int ret; + char *config_file; + struct play_cmdline_parser_params params = { + .override = 0, + .initialize = 1, + .check_required = 0, + .check_ambiguity = 0, + .print_errors = 1 + }; + + if (play_cmdline_parser_ext(argc, argv, &conf, ¶ms)) + exit(EXIT_FAILURE); + HANDLE_VERSION_FLAG("play", conf); + if (conf.help_given || conf.detailed_help_given) + print_help_and_die(); + loglevel = get_loglevel_by_name(conf.loglevel_arg); + if (conf.config_file_given) + config_file = para_strdup(conf.config_file_arg); + else { + char *home = para_homedir(); + config_file = make_message("%s/.paraslash/play.conf", home); + free(home); + } + ret = file_exists(config_file); + if (conf.config_file_given && !ret) { + PARA_EMERG_LOG("can not read config file %s\n", config_file); + goto err; + } + if (ret) { + params.initialize = 0; + params.check_required = 1; + play_cmdline_parser_config_file(config_file, &conf, ¶ms); + } + free(config_file); + return; +err: + free(config_file); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + /* needed this early to make help work */ + recv_init(); + filter_init(); + writer_init(); + + parse_config_or_die(argc, argv); + return 0; +} diff --git a/play.cmd b/play.cmd new file mode 100644 index 00000000..c0e8d7f1 --- /dev/null +++ b/play.cmd @@ -0,0 +1,8 @@ +BN: play +SF: play.c +SN: list of commands +--- +N: quit +D: Exit para_play. +U: quit +H: Pressing CTRL+D causes EOF on stdin which also exits para_play. diff --git a/server.c b/server.c index 8e8cb5fd..5d4a9fe7 100644 --- a/server.c +++ b/server.c @@ -14,7 +14,7 @@ * * * - The main programs: \ref server.c, \ref audiod.c, \ref client.c, - * \ref audioc.c, \ref afh.c + * \ref audioc.c, \ref afh.c, \ref play.c, * - Server: \ref server_command, \ref sender, * - Audio file selector: \ref audio_format_handler, \ref afs_table, * - Client: \ref receiver, \ref receiver_node, \ref filter, diff --git a/web/manual.m4 b/web/manual.m4 index 5ceeac08..3ebeb6b0 100644 --- a/web/manual.m4 +++ b/web/manual.m4 @@ -174,6 +174,9 @@ output plug-in and optional WAV/raw players for ALSA (Linux) and for coreaudio (Mac OS). para_write can also be used as a stand-alone WAV or raw audio player. +*para_play* + +A command line audio player. *para_gui* @@ -274,7 +277,8 @@ Optional: - XREFERENCE(http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html, GNU Readline). If this library (libreadline-dev) is installed, - para_client and para_audioc support interactive sessions. + para_client, para_audioc and para_play support interactive + sessions. Installation ~~~~~~~~~~~~ -- 2.39.5