diff --git a/Makefile.am b/Makefile.am index 09dc0da..044611a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,7 @@ EXTRA_DIST += \ NEWS.libout123 \ NEWS.libsyn123 \ ports/cmake/CMakeLists.txt \ + ports/cmake/linux_i686.toolchain.cmake \ ports/cmake/mpg123-config.cmake.in \ ports/cmake/cmake/search_libs.cmake \ ports/cmake/cmake/read_api_version.cmake \ diff --git a/Makefile.in b/Makefile.in index fc42a4e..1ea1286 100644 --- a/Makefile.in +++ b/Makefile.in @@ -375,22 +375,23 @@ check_PROGRAMS = src/tests/decode_fixed$(EXEEXT) \ @TERM_POSIX_TRUE@am__append_98 = src/term_posix.c @TERM_WIN32_TRUE@am__append_99 = src/term_win32.c @TERM_NONE_TRUE@am__append_100 = src/term_none.c -@NET123_EXEC_TRUE@am__append_101 = src/net123.h src/net123_exec.c -@NET123_WINHTTP_TRUE@am__append_102 = src/net123.h src/net123_winhttp.c -@NET123_WINHTTP_TRUE@am__append_103 = -lwinhttp -@NET123_WININET_TRUE@am__append_104 = src/net123.h src/net123_wininet.c -@NET123_WININET_TRUE@am__append_105 = -lwininet -@WIN32_CODES_TRUE@am__append_106 = \ -@WIN32_CODES_TRUE@ src/win32_support.c - -@NETWORK_WINSOCK_TRUE@@WIN32_CODES_TRUE@am__append_107 = src/win32_net.c -@NETWORK_WINSOCK_TRUE@@WIN32_CODES_TRUE@am__append_108 = -lws2_32 -@WIN32_CODES_TRUE@am__append_109 = \ +@NET123_TRUE@am__append_101 = src/net123.h +@NET123_EXEC_TRUE@am__append_102 = src/net123_exec.c +@NET123_WINHTTP_TRUE@am__append_103 = src/net123_winhttp.c +@NET123_WINHTTP_TRUE@am__append_104 = -lwinhttp +@NET123_WININET_TRUE@am__append_105 = src/net123_wininet.c +@NET123_WININET_TRUE@am__append_106 = -lwininet +@WIN32_CODES_TRUE@am__append_107 = \ @WIN32_CODES_TRUE@ src/win32_support.c +@NETWORK_WINSOCK_TRUE@@WIN32_CODES_TRUE@am__append_108 = src/win32_net.c +@NETWORK_WINSOCK_TRUE@@WIN32_CODES_TRUE@am__append_109 = -lws2_32 @WIN32_CODES_TRUE@am__append_110 = \ @WIN32_CODES_TRUE@ src/win32_support.c +@WIN32_CODES_TRUE@am__append_111 = \ +@WIN32_CODES_TRUE@ src/win32_support.c + subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ @@ -1128,11 +1129,12 @@ am__src_mpg123_SOURCES_DIST = src/audio.c src/audio.h src/common.c \ @TERM_POSIX_TRUE@am__objects_70 = src/term_posix.$(OBJEXT) @TERM_WIN32_TRUE@am__objects_71 = src/term_win32.$(OBJEXT) @TERM_NONE_TRUE@am__objects_72 = src/term_none.$(OBJEXT) -@NET123_EXEC_TRUE@am__objects_73 = src/net123_exec.$(OBJEXT) -@NET123_WINHTTP_TRUE@am__objects_74 = src/net123_winhttp.$(OBJEXT) -@NET123_WININET_TRUE@am__objects_75 = src/net123_wininet.$(OBJEXT) -@WIN32_CODES_TRUE@am__objects_76 = src/win32_support.$(OBJEXT) -@NETWORK_WINSOCK_TRUE@@WIN32_CODES_TRUE@am__objects_77 = src/win32_net.$(OBJEXT) +am__objects_73 = +@NET123_EXEC_TRUE@am__objects_74 = src/net123_exec.$(OBJEXT) +@NET123_WINHTTP_TRUE@am__objects_75 = src/net123_winhttp.$(OBJEXT) +@NET123_WININET_TRUE@am__objects_76 = src/net123_wininet.$(OBJEXT) +@WIN32_CODES_TRUE@am__objects_77 = src/win32_support.$(OBJEXT) +@NETWORK_WINSOCK_TRUE@@WIN32_CODES_TRUE@am__objects_78 = src/win32_net.$(OBJEXT) am_src_mpg123_OBJECTS = src/audio.$(OBJEXT) src/common.$(OBJEXT) \ src/sysutil.$(OBJEXT) src/control_generic.$(OBJEXT) \ src/equalizer.$(OBJEXT) src/getlopt.$(OBJEXT) \ @@ -1142,7 +1144,8 @@ am_src_mpg123_OBJECTS = src/audio.$(OBJEXT) src/common.$(OBJEXT) \ src/playlist.$(OBJEXT) src/streamdump.$(OBJEXT) \ src/term.$(OBJEXT) $(am__objects_70) $(am__objects_71) \ $(am__objects_72) $(am__objects_73) $(am__objects_74) \ - $(am__objects_75) $(am__objects_76) $(am__objects_77) + $(am__objects_75) $(am__objects_76) $(am__objects_77) \ + $(am__objects_78) src_mpg123_OBJECTS = $(am_src_mpg123_OBJECTS) am__DEPENDENCIES_1 = src_mpg123_DEPENDENCIES = src/compat/libcompat.la \ @@ -1155,7 +1158,7 @@ src_mpg123_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ am__src_mpg123_id3dump_SOURCES_DIST = src/mpg123-id3dump.c \ src/getlopt.c src/getlopt.h src/win32_support.c am_src_mpg123_id3dump_OBJECTS = src/mpg123-id3dump.$(OBJEXT) \ - src/getlopt.$(OBJEXT) $(am__objects_76) + src/getlopt.$(OBJEXT) $(am__objects_77) src_mpg123_id3dump_OBJECTS = $(am_src_mpg123_id3dump_OBJECTS) src_mpg123_id3dump_DEPENDENCIES = src/compat/libcompat.la \ src/libmpg123/libmpg123.la @@ -1170,7 +1173,7 @@ am__src_out123_SOURCES_DIST = src/sysutil.c src/sysutil.h src/common.h \ src/win32_support.h src/win32_support.c am_src_out123_OBJECTS = src/sysutil.$(OBJEXT) src/getlopt.$(OBJEXT) \ src/local.$(OBJEXT) src/filters.$(OBJEXT) src/out123.$(OBJEXT) \ - $(am__objects_76) + $(am__objects_77) src_out123_OBJECTS = $(am_src_out123_OBJECTS) src_out123_DEPENDENCIES = src/compat/libcompat.la \ src/libsyn123/libsyn123.la src/libout123/libout123.la @@ -2031,7 +2034,9 @@ EXTRA_DIST = src/tests/testtext.sh src/tests/decode_fixed.sh \ doc/examples/dump_seekindex.c doc/examples/extract_frames.c \ doc/examples/Makefile mpg123.spec makedll.sh windows-builds.sh \ equalize.dat NEWS.libmpg123 NEWS.libout123 NEWS.libsyn123 \ - ports/cmake/CMakeLists.txt ports/cmake/mpg123-config.cmake.in \ + ports/cmake/CMakeLists.txt \ + ports/cmake/linux_i686.toolchain.cmake \ + ports/cmake/mpg123-config.cmake.in \ ports/cmake/cmake/search_libs.cmake \ ports/cmake/cmake/read_api_version.cmake \ ports/cmake/cmake/CheckCPUArch.cmake \ @@ -2880,8 +2885,8 @@ src_libsyn123_libsyn123_la_SOURCES = \ src_mpg123_LDADD = src/compat/libcompat.la src/libmpg123/libmpg123.la \ src/libout123/libout123.la src/libsyn123/libsyn123.la \ - @PROG_LIBS@ $(am__append_103) $(am__append_105) \ - $(am__append_108) + @PROG_LIBS@ $(am__append_104) $(am__append_106) \ + $(am__append_109) src_mpg123_LDFLAGS = @EXEC_LT_LDFLAGS@ src_out123_LDADD = \ src/compat/libcompat.la \ @@ -2911,16 +2916,16 @@ src_mpg123_SOURCES = src/audio.c src/audio.h src/common.c src/common.h \ src/playlist.h src/streamdump.h src/streamdump.c src/term.c \ src/term.h src/terms.h src/win32_support.h $(am__append_98) \ $(am__append_99) $(am__append_100) $(am__append_101) \ - $(am__append_102) $(am__append_104) $(am__append_106) \ - $(am__append_107) + $(am__append_102) $(am__append_103) $(am__append_105) \ + $(am__append_107) $(am__append_108) # Replace common.h by sysutil.h! src_out123_SOURCES = src/sysutil.c src/sysutil.h src/common.h \ src/getlopt.c src/getlopt.h src/local.h src/local.c \ src/filters.h src/filters.c src/out123.c src/mpg123app.h \ - src/win32_support.h $(am__append_109) + src/win32_support.h $(am__append_110) src_mpg123_id3dump_SOURCES = src/mpg123-id3dump.c src/getlopt.c \ - src/getlopt.h $(am__append_110) + src/getlopt.h $(am__append_111) src_mpg123_strip_SOURCES = \ src/mpg123-strip.c \ src/getlopt.c \ diff --git a/NEWS b/NEWS index ea49031..6228b81 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,50 @@ +1.31.0 +------ + +- mpg123: +-- Finally make terminal control work on Windows, for real. Building it + was broken in 1.30.x. +-- The --control / -C switch will make mpg123 abort now if terminal + control cannot be enabled. +-- Revert to internal network code for plain HTTP to ensure continued + support for original shoutcast servers that do not talk proper HTTP. + External backends are built at the same time and can be enforced using + --network . +-- Try-witout-port for internal network code is gone. We do not need to + keep each ancient hack for specific hosts. +-- Handle redirections independently of the backend behind net123. +-- Set proxy environment variables when --proxy is specified, for net123 + backends to use. +-- Continue reading for long commands in generic control, avoiding + unnecessary unfinished command errors. +-- Change error message from 'unknown command' to + 'unknown command with arguments' to avoid confusion why 'help foo' + is unknown, as opposed to 'help'. +-- Reduce CPU load while just waiting for terminal input + (thanks to bolshoytoster on github). +-- Condense terminal control help output and excessive vertical whitespace + in printouts (inspired by Volkmar Klatt). +-- Fix interaction of pause (looping) with buffer, adding --pauseloop + to set the loop interval. +-- Numeric option arguments are strictly checked now for conversion errors. + This also catches -devbuffer, which was interpretd as -d 0 before. This + also applies to out123. +- libout123: +-- Add same interruption handling to out123_write() as to + unintr_write(), adding EAGAIN to fix bug 342 (thanks to Steffen Nurpmeso) + for certain ALSA setups. +-- Add --devbuffer support to win32 output and change default to 0.25 seconds. +-- Fix race condition to deadlock on buffer_sync_param() where parameters after + the command byte got read as more commands. This got triggered easily by + using the pause key in terminal mode with buffer (which was discouraged + before because of buffer flushing). Generally, changing parameters with + active buffer process was dangerous since libout123 entered the scene. +- some build fixes for compiler pickyness +- Disable largefile renames also for non-sensitive POSIX systems + (in some distant future, the alias symbols could go away, then … + bug 330). +- Fix Android NDK x86 builds with GLOBAL_VAR_PTR use in assembly (bug 345). + 1.30.2 ------ - Only use EWOULDBLOCK if the macro is defined (FreeBSD misses it for diff --git a/configure b/configure index 7630b08..eca6fe5 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for mpg123 1.30.2. +# Generated by GNU Autoconf 2.69 for mpg123 1.31.0. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mpg123' PACKAGE_TARNAME='mpg123' -PACKAGE_VERSION='1.30.2' -PACKAGE_STRING='mpg123 1.30.2' +PACKAGE_VERSION='1.31.0' +PACKAGE_STRING='mpg123 1.31.0' PACKAGE_BUGREPORT='maintainer@mpg123.org' PACKAGE_URL='' @@ -653,6 +653,8 @@ NET123_WINHTTP_FALSE NET123_WINHTTP_TRUE NET123_EXEC_FALSE NET123_EXEC_TRUE +NET123_FALSE +NET123_TRUE NETWORK_WINSOCK_FALSE NETWORK_WINSOCK_TRUE WIN32_CODES_FALSE @@ -793,9 +795,7 @@ SUN_LDFLAGS SUN_LIBS HAVE_SNDIO_FALSE HAVE_SNDIO_TRUE -SNDIO_CFLAGS SNDIO_LDFLAGS -SNDIO_LIBS HAVE_COREAUDIO_FALSE HAVE_COREAUDIO_TRUE COREAUDIO_CFLAGS @@ -821,6 +821,8 @@ HAVE_TINYALSA_TRUE TINYALSA_CFLAGS TINYALSA_LDFLAGS TINYALSA_LIBS +SNDIO_LIBS +SNDIO_CFLAGS SDL_LIBS SDL_CFLAGS ESD_LIBS @@ -888,10 +890,10 @@ HAVE_FLOATDCT_TRUE INCLUDE_SYS_TYPE_H INCLUDE_STDLIB_H INCLUDE_STDIO_H -BUILD_NO_LARGENAME HAVE_LFS_ALIAS_FALSE HAVE_LFS_ALIAS_TRUE LFS_ALIAS_BITS +BUILD_NO_LARGENAME HAVE_LFS_WRAP_FALSE HAVE_LFS_WRAP_TRUE YASMFLAGS @@ -1132,7 +1134,9 @@ PULSE_LIBS ESD_CFLAGS ESD_LIBS SDL_CFLAGS -SDL_LIBS' +SDL_LIBS +SNDIO_CFLAGS +SNDIO_LIBS' # Initialize some variables set by options. @@ -1683,7 +1687,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures mpg123 1.30.2 to adapt to many kinds of systems. +\`configure' configures mpg123 1.31.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1754,7 +1758,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mpg123 1.30.2:";; + short | recursive ) echo "Configuration of mpg123 1.31.0:";; esac cat <<\_ACEOF @@ -1891,8 +1895,12 @@ Optional Packages: --with-seektable= choose size of seek index table (0 disables it), default 1000 --with-network= Available options, depending on platform, are auto, - none, internal, winhttp, wininet, and exec (wget or - curl binaries). + none, internal, winhttp, wininet (or wininethttp for + both), and exec (wget or curl binaries). The + internal code is always built in addition to + external options for plain HTTP (esp. Shoutcast v1) + support. The external option is for HTTPS by + default, but can be used for HTTP, too. Some influential environment variables: CC C compiler command @@ -1921,6 +1929,9 @@ Some influential environment variables: ESD_LIBS linker flags for ESD, overriding pkg-config SDL_CFLAGS C compiler flags for SDL, overriding pkg-config SDL_LIBS linker flags for SDL, overriding pkg-config + SNDIO_CFLAGS + C compiler flags for SNDIO, overriding pkg-config + SNDIO_LIBS linker flags for SNDIO, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1988,7 +1999,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mpg123 configure 1.30.2 +mpg123 configure 1.31.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2594,7 +2605,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by mpg123 $as_me 1.30.2, which was +It was created by mpg123 $as_me 1.31.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2947,7 +2958,7 @@ API_VERSION=47 LIB_PATCHLEVEL=0 OUTAPI_VERSION=4 -OUTLIB_PATCHLEVEL=4 +OUTLIB_PATCHLEVEL=7 SYNAPI_VERSION=1 SYNLIB_PATCHLEVEL=4 @@ -3553,7 +3564,7 @@ fi # Define the identity of the package. PACKAGE='mpg123' - VERSION='1.30.2' + VERSION='1.31.0' cat >>confdefs.h <<_ACEOF @@ -15594,8 +15605,10 @@ fi if test "x$ac_cv_sys_file_offset_bits" = x || echo "$ac_cv_sys_file_offset_bits" | $GREP '[^0-9]' > /dev/null; then largefile_sensitive=no + BUILD_NO_LARGENAME=1 else largefile_sensitive=yes + BUILD_NO_LARGENAME=0 fi # Add dual-mode wrapper code. if test x"$largefile_sensitive" = xyes ; then @@ -15606,6 +15619,8 @@ else HAVE_LFS_WRAP_FALSE= fi +# Any non-sensitive platform does not bother with off_t-based function renaming. + # Using the lower level macros instead of AC_TYPE_* for compatibility with not freshest autoconf. ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" @@ -16021,7 +16036,6 @@ done fi -term_type=none # Check if system supports termios { $as_echo "$as_me:${as_lineno-$LINENO}: checking POSIX termios" >&5 $as_echo_n "checking POSIX termios... " >&6; } @@ -16054,6 +16068,34 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_posix_termios" >&5 $as_echo "$ac_cv_sys_posix_termios" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have wincon.h" >&5 +$as_echo_n "checking if we have wincon.h... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +void *v = &ReadConsoleInput; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_wincon_h=yes +else + ac_cv_header_wincon_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_wincon_h" >&5 +$as_echo "$ac_cv_header_wincon_h" >&6; } +if test "x$ac_cv_header_wincon_h" = "xyes"; then : + +else + +$as_echo "#define HAVE_WINCON_H 1" >>confdefs.h + +fi + +term_type=none if test "x$ac_cv_sys_posix_termios" = "xyes"; then cat >>confdefs.h <<_ACEOF @@ -16061,9 +16103,12 @@ cat >>confdefs.h <<_ACEOF _ACEOF term_type=posix +elif test "x$ac_cv_header_windows_h" = "xyes" && + test "x$ac_cv_header_wincon_h" = "xyes"; then + term_type=win32 fi -for ac_func in random +for ac_func in random setenv unsetenv do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -16396,13 +16441,6 @@ fi done -# A Hack for MSVC builds by cmake: Disable largefile hackery. -# Maybe one time we support hat wretched environment directly, but -# for now configure lives in a world where large file support is -# properly defined and served by off_t. -BUILD_NO_LARGENAME=0 - - # Substitutions for the installable mpg123.h header if test "x$ac_cv_header_stdio_h" = "xyes"; then INCLUDE_STDIO_H="#include " @@ -18114,63 +18152,77 @@ $as_echo "$HAVE_WIN32_WASAPI" >&6; } fi ;; sndio) - SNDIO_LIBS=-lsndio - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sio_open in -lsndio" >&5 -$as_echo_n "checking for sio_open in -lsndio... " >&6; } -if ${ac_cv_lib_sndio_sio_open+:} false; then : - $as_echo_n "(cached) " >&6 + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SNDIO" >&5 +$as_echo_n "checking for SNDIO... " >&6; } + +if test -n "$SNDIO_CFLAGS"; then + pkg_cv_SNDIO_CFLAGS="$SNDIO_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sndio\""; } >&5 + ($PKG_CONFIG --exists --print-errors "sndio") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SNDIO_CFLAGS=`$PKG_CONFIG --cflags "sndio" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsndio $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char sio_open (); -int -main () -{ -return sio_open (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_sndio_sio_open=yes + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$SNDIO_LIBS"; then + pkg_cv_SNDIO_LIBS="$SNDIO_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sndio\""; } >&5 + ($PKG_CONFIG --exists --print-errors "sndio") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SNDIO_LIBS=`$PKG_CONFIG --libs "sndio" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes else - ac_cv_lib_sndio_sio_open=no + pkg_failed=yes fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sndio_sio_open" >&5 -$as_echo "$ac_cv_lib_sndio_sio_open" >&6; } -if test "x$ac_cv_lib_sndio_sio_open" = xyes; then : - for ac_header in sndio.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sndio.h" "ac_cv_header_sndio_h" "$ac_includes_default" -if test "x$ac_cv_header_sndio_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SNDIO_H 1 -_ACEOF - output_modules="$output_modules sndio" HAVE_SNDIO="yes" + else + pkg_failed=untried fi -done +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no fi + if test $_pkg_short_errors_supported = yes; then + SNDIO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sndio" 2>&1` + else + SNDIO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sndio" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$SNDIO_PKG_ERRORS" >&5 - if test "x$HAVE_SNDIO" != xyes; then - check_failed=yes - fi + HAVE_SNDIO="no" check_failed=yes +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_SNDIO="no" check_failed=yes +else + SNDIO_CFLAGS=$pkg_cv_SNDIO_CFLAGS + SNDIO_LIBS=$pkg_cv_SNDIO_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + output_modules="$output_modules sndio" HAVE_SNDIO="yes" +fi ;; sun) for ac_header in sun/audioio.h sys/audioio.h asm/audioio.h sys/audio.h @@ -18805,11 +18857,11 @@ fi #for i in dummy tinyalsa alsa qsa coreaudio esd jack nas oss portaudio pulse sdl sndio sun win32 win32_wasapi aix alib arts hp os2 sgi mint openal #do echo $i; done | #perl -ne 'chomp; $big = uc($_); print <&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: wininet" >&5 $as_echo "wininet" >&6; } ;; + wininethttp) + network_type="wininethttp" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: wininethttp" >&5 +$as_echo "wininethttp" >&6; } + ;; internal) network_type="internal" { $as_echo "$as_me:${as_lineno-$LINENO}: result: internal" >&5 @@ -19559,7 +19616,7 @@ $as_echo_n "checking for automatic network support... " >&6; } if test "x$have_fork" = "xyes"; then network_type=exec elif test "x$win32_specific_codes" = "xenabled"; then - network_type=wininet + network_type=wininethttp elif test "x$have_network" = "xyes"; then network_type="internal" else @@ -19578,7 +19635,7 @@ fi if test x$network_type = xexec -a x$have_fork != xyes; then as_fn_error $? "exec network support selected but fork not available" "$LINENO" 5 fi -if test x$network_type = xwininet -o x$network_type = xwinhttp && test x$win32_specific_codes != xenabled; then +if test x$network_type = xwininet -o x$network_type = xwinhttp -o x$network_type = xwininethttp && test x$win32_specific_codes != xenabled; then as_fn_error $? "wininet or winhttp is currently only for Windows" "$LINENO" 5 fi @@ -19595,7 +19652,7 @@ fi if test x"$ipv6" = xauto; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking IPv6 use" >&5 $as_echo_n "checking IPv6 use... " >&6; } - if test x"$have_ipv6" = xyes -a x"$network_type" = xinternal; then + if test x"$have_ipv6" = xyes -a x"$network_type" != xdisabled; then ipv6=enabled else ipv6=disabled @@ -19604,13 +19661,13 @@ $as_echo_n "checking IPv6 use... " >&6; } $as_echo "$ipv6" >&6; } fi -if test x$network_type = xinternal -a x$network_internal = xwinsock2; then +if test x$network_type != xdisabled -a x$network_internal = xwinsock2; then $as_echo "#define WANT_WIN32_SOCKETS 1" >>confdefs.h fi - if test x$network_type = xinternal -a x$network_internal = xwinsock2 ; then + if test x$network_type != xdisabled -a x$network_internal = xwinsock2 ; then NETWORK_WINSOCK_TRUE= NETWORK_WINSOCK_FALSE='#' else @@ -19618,6 +19675,14 @@ else NETWORK_WINSOCK_FALSE= fi + if test x$network_type != xdisabled ; then + NET123_TRUE= + NET123_FALSE='#' +else + NET123_TRUE='#' + NET123_FALSE= +fi + if test x$network_type = xexec ; then NET123_EXEC_TRUE= NET123_EXEC_FALSE='#' @@ -19626,7 +19691,7 @@ else NET123_EXEC_FALSE= fi - if test x$network_type = xwinhttp ; then + if test x$network_type = xwinhttp || test x$network_type = xwininethttp ; then NET123_WINHTTP_TRUE= NET123_WINHTTP_FALSE='#' else @@ -19634,7 +19699,7 @@ else NET123_WINHTTP_FALSE= fi - if test x$network_type = xwininet ; then + if test x$network_type = xwininet || test x$network_type = xwininethttp ; then NET123_WININET_TRUE= NET123_WININET_FALSE='#' else @@ -19643,6 +19708,32 @@ else fi +case "$network_type" in + exec) + +$as_echo "#define NET123_EXEC 1" >>confdefs.h + + ;; + winhttp) + +$as_echo "#define NET123_WINHTTP 1" >>confdefs.h + + ;; + wininet) + +$as_echo "#define NET123_WININET 1" >>confdefs.h + + ;; + wininethttp) + +$as_echo "#define NET123_WININET 1" >>confdefs.h + + +$as_echo "#define NET123_WINHTTP 1" >>confdefs.h + + ;; +esac + if test "x$term_type" = xposix ; then TERM_POSIX_TRUE= @@ -19688,7 +19779,7 @@ $as_echo "$as_me: WARNING: You forced FIFO code while I think there is no mkfif fi fi -if test x"$network_type" = xinternal; then +if test x"$network_type" != xdisabled; then $as_echo "#define NETWORK 1" >>confdefs.h @@ -20235,6 +20326,10 @@ if test -z "${NETWORK_WINSOCK_TRUE}" && test -z "${NETWORK_WINSOCK_FALSE}"; then as_fn_error $? "conditional \"NETWORK_WINSOCK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${NET123_TRUE}" && test -z "${NET123_FALSE}"; then + as_fn_error $? "conditional \"NET123\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${NET123_EXEC_TRUE}" && test -z "${NET123_EXEC_FALSE}"; then as_fn_error $? "conditional \"NET123_EXEC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -20656,7 +20751,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by mpg123 $as_me 1.30.2, which was +This file was extended by mpg123 $as_me 1.31.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -20722,7 +20817,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -mpg123 config.status 1.30.2 +mpg123 config.status 1.31.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -22433,9 +22528,11 @@ echo " Extreme debugging ....... $xdebugging Seek table size ......... $seektable FIFO support ............ $fifo - Buffer .................. $buffer - Network (http streams) .. $network_type" -if test x$network_type = xinternal; then + Buffer .................. $buffer" +if test x$network_type != xdisabled; then + if test x$network_type != xinternal; then + echo " External network ........ $network_type" + fi echo " Internal network type ... $network_internal IPv6 (getaddrinfo) ...... $ipv6" fi diff --git a/configure.ac b/configure.ac index 9e6d91b..4074711 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ dnl 2.69 at least. AC_PREREQ([2.69]) dnl ############# Initialisation -AC_INIT([mpg123], [1.30.2], [maintainer@mpg123.org]) +AC_INIT([mpg123], [1.31.0], [maintainer@mpg123.org]) dnl Increment API_VERSION when the API gets changes (new functions). dnl libmpg123 @@ -18,7 +18,7 @@ LIB_PATCHLEVEL=0 dnl libout123 OUTAPI_VERSION=4 -OUTLIB_PATCHLEVEL=4 +OUTLIB_PATCHLEVEL=7 dnl libsyn123 SYNAPI_VERSION=1 @@ -1126,11 +1126,15 @@ dnl sensitive to largefile changes, i.e. FreeBSD always using 64 bit off_t. if test "x$ac_cv_sys_file_offset_bits" = x || echo "$ac_cv_sys_file_offset_bits" | $GREP '@<:@^0-9@:>@' > /dev/null; then dnl if it has non-numeric chars or is empty... ignore... largefile_sensitive=no + BUILD_NO_LARGENAME=1 else largefile_sensitive=yes + BUILD_NO_LARGENAME=0 fi # Add dual-mode wrapper code. AM_CONDITIONAL([HAVE_LFS_WRAP], [ test x"$largefile_sensitive" = xyes ] ) +# Any non-sensitive platform does not bother with off_t-based function renaming. +AC_SUBST(BUILD_NO_LARGENAME) # Using the lower level macros instead of AC_TYPE_* for compatibility with not freshest autoconf. AC_CHECK_TYPE(size_t, unsigned long) @@ -1209,16 +1213,29 @@ if test "x$have_mmap" = "xno"; then AC_CHECK_FUNCS([shmget shmat shmdt shmctl],[], [buffer=disabled]) fi -term_type=none # Check if system supports termios AC_SYS_POSIX_TERMIOS + +AC_MSG_CHECKING([if we have wincon.h]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +#include +#include +void *v = &ReadConsoleInput; +])],[ac_cv_header_wincon_h=yes],[ac_cv_header_wincon_h=no]) +AC_MSG_RESULT([$ac_cv_header_wincon_h]) +AS_IF([test "x$ac_cv_header_wincon_h" = "xyes"],[],[AC_DEFINE([HAVE_WINCON_H],[1],[Define to 1 if you have the header file.])]) + +term_type=none if test "x$ac_cv_sys_posix_termios" = "xyes"; then AC_DEFINE_UNQUOTED([HAVE_TERMIOS], 1, [Define this if you have the POSIX termios library]) term_type=posix +elif test "x$ac_cv_header_windows_h" = "xyes" && + test "x$ac_cv_header_wincon_h" = "xyes"; then + term_type=win32 fi -AC_CHECK_FUNCS( random ) +AC_CHECK_FUNCS( random setenv unsetenv ) # Check for sched_setscheduler AC_CHECK_FUNCS( sched_setscheduler setuid getuid) @@ -1292,13 +1309,6 @@ AC_SEARCH_LIBS(socket, socket) AC_CHECK_FUNCS( getaddrinfo, [ have_ipv6=yes ], [ have_ipv6=no ] ) -# A Hack for MSVC builds by cmake: Disable largefile hackery. -# Maybe one time we support hat wretched environment directly, but -# for now configure lives in a world where large file support is -# properly defined and served by off_t. -BUILD_NO_LARGENAME=0 -AC_SUBST(BUILD_NO_LARGENAME) - # Substitutions for the installable mpg123.h header if test "x$ac_cv_header_stdio_h" = "xyes"; then INCLUDE_STDIO_H="#include " @@ -1885,15 +1895,7 @@ int main(){ fi ;; sndio) - SNDIO_LIBS=-lsndio - AC_CHECK_LIB([sndio], [sio_open], - [AC_CHECK_HEADERS([sndio.h], - [output_modules="$output_modules sndio" HAVE_SNDIO="yes"]) - ] - ) - if test "x$HAVE_SNDIO" != xyes; then - check_failed=yes - fi + PKG_CHECK_MODULES(SNDIO, sndio, output_modules="$output_modules sndio" HAVE_SNDIO="yes", HAVE_SNDIO="no" check_failed=yes) ;; sun) AC_CHECK_HEADERS([sun/audioio.h sys/audioio.h asm/audioio.h sys/audio.h]) @@ -2214,34 +2216,34 @@ fi #for i in dummy tinyalsa alsa qsa coreaudio esd jack nas oss portaudio pulse sdl sndio sun win32 win32_wasapi aix alib arts hp os2 sgi mint openal #do echo $i; done | #perl -ne 'chomp; $big = uc($_); print <], [Available options, depending on platform, are auto, none, internal, winhttp, wininet, and exec (wget or curl binaries).])], + [AS_HELP_STRING([--with-network=], +[Available options, depending on platform, are auto, none, internal, winhttp, wininet (or wininethttp for both), and exec (wget or curl binaries). +The internal code is always built in addition to external options for plain HTTP (esp. Shoutcast v1) support. +The external option is for HTTPS by default, but can be used for HTTP, too.])], [ case "$withval" in exec) @@ -2592,6 +2597,10 @@ AC_ARG_WITH([network], network_type="wininet" AC_MSG_RESULT([wininet]) ;; + wininethttp) + network_type="wininethttp" + AC_MSG_RESULT([wininethttp]) + ;; internal) network_type="internal" AC_MSG_RESULT([internal]) @@ -2619,7 +2628,7 @@ if test x$network_type = xauto; then if test "x$have_fork" = "xyes"; then network_type=exec elif test "x$win32_specific_codes" = "xenabled"; then - network_type=wininet + network_type=wininethttp elif test "x$have_network" = "xyes"; then network_type="internal" else @@ -2635,7 +2644,7 @@ fi if test x$network_type = xexec -a x$have_fork != xyes; then AC_MSG_ERROR([exec network support selected but fork not available]) fi -if test x$network_type = xwininet -o x$network_type = xwinhttp && test x$win32_specific_codes != xenabled; then +if test x$network_type = xwininet -o x$network_type = xwinhttp -o x$network_type = xwininethttp && test x$win32_specific_codes != xenabled; then AC_MSG_ERROR([wininet or winhttp is currently only for Windows]) fi @@ -2644,7 +2653,7 @@ AM_CONDITIONAL([WIN32_CODES], [ test "x$win32_specific_codes" = xenabled ]) if test x"$ipv6" = xauto; then AC_MSG_CHECKING([IPv6 use]) - if test x"$have_ipv6" = xyes -a x"$network_type" = xinternal; then + if test x"$have_ipv6" = xyes -a x"$network_type" != xdisabled; then ipv6=enabled else ipv6=disabled @@ -2652,14 +2661,31 @@ if test x"$ipv6" = xauto; then AC_MSG_RESULT([$ipv6]) fi -if test x$network_type = xinternal -a x$network_internal = xwinsock2; then +if test x$network_type != xdisabled -a x$network_internal = xwinsock2; then AC_DEFINE([WANT_WIN32_SOCKETS], [1], [ Define to use Win32 sockets ]) fi -AM_CONDITIONAL([NETWORK_WINSOCK], [ test x$network_type = xinternal -a x$network_internal = xwinsock2 ]) +AM_CONDITIONAL([NETWORK_WINSOCK], [ test x$network_type != xdisabled -a x$network_internal = xwinsock2 ]) +AM_CONDITIONAL([NET123], [ test x$network_type != xdisabled ]) AM_CONDITIONAL([NET123_EXEC], [ test x$network_type = xexec ]) -AM_CONDITIONAL([NET123_WINHTTP], [ test x$network_type = xwinhttp ]) -AM_CONDITIONAL([NET123_WININET], [ test x$network_type = xwininet ]) +AM_CONDITIONAL([NET123_WINHTTP], [ test x$network_type = xwinhttp || test x$network_type = xwininethttp ]) +AM_CONDITIONAL([NET123_WININET], [ test x$network_type = xwininet || test x$network_type = xwininethttp ]) + +case "$network_type" in + exec) + AC_DEFINE(NET123_EXEC, 1, [ Define for executable-based networking (for HTTPS). ]) + ;; + winhttp) + AC_DEFINE(NET123_WINHTTP, 1, [ Define for winhttp networking (for HTTPS). ]) + ;; + wininet) + AC_DEFINE(NET123_WININET, 1, [ Define for wininet networking (for HTTPS). ]) + ;; + wininethttp) + AC_DEFINE(NET123_WININET, 1, [ Define for wininet networking (for HTTPS). ]) + AC_DEFINE(NET123_WINHTTP, 1, [ Define for winhttp networking (for HTTPS). ]) + ;; +esac dnl ############## Terminal choice @@ -2685,7 +2711,7 @@ if test x"$fifo" = xenabled; then fi dnl ############## Network enable -if test x"$network_type" = xinternal; then +if test x"$network_type" != xdisabled; then AC_DEFINE(NETWORK, 1, [ Define if network support is enabled. ]) if test x"$have_network" = xno; then AC_MSG_WARN( [ You forced network code while I think there is support missing! ] ) @@ -2742,9 +2768,11 @@ echo " Extreme debugging ....... $xdebugging Seek table size ......... $seektable FIFO support ............ $fifo - Buffer .................. $buffer - Network (http streams) .. $network_type" -if test x$network_type = xinternal; then + Buffer .................. $buffer" +if test x$network_type != xdisabled; then + if test x$network_type != xinternal; then + echo " External network ........ $network_type" + fi echo " Internal network type ... $network_internal IPv6 (getaddrinfo) ...... $ipv6" fi diff --git a/man1/mpg123.1 b/man1/mpg123.1 index 36666a8..0d96f8f 100644 --- a/man1/mpg123.1 +++ b/man1/mpg123.1 @@ -421,6 +421,10 @@ Disable terminal control even if terminal is detected. In an xterm, rxvt, screen, iris-ansi (compatible, TERM environment variable is examined), change the window's title to the name of song currently playing. .TP +\fB\-\^\-pauseloop \fIseconds +Set the length of the loop interval in terminal control paused mode, away from the default of 0.5 seconds, as a floating +point number. +.TP \fB\-\^\-name \fIname Set the name of this instance, possibly used in various places. This sets the client name for JACK output. .TP diff --git a/mpg123.spec b/mpg123.spec index 96ab78e..1e231ae 100644 --- a/mpg123.spec +++ b/mpg123.spec @@ -3,7 +3,7 @@ # - devel packages for alsa, sdl, etc... to build the respective output modules. Summary: The fast console mpeg audio decoder/player. Name: mpg123 -Version: 1.30.2 +Version: 1.31.0 Release: 1 URL: http://www.mpg123.org/ License: GPL diff --git a/ports/README b/ports/README index 5b426a6..54dc117 100644 --- a/ports/README +++ b/ports/README @@ -11,15 +11,7 @@ sources); as the team lacks resource to test everything. But in any case, the ports can provide a good starting point on the respective platform, to get it to work with minimal fuzz. -- cmake: CMake build to get started on non-Unix-like platforms -- Delphi: mpg123_.pas - Unit for linking against libmpg123 (Win32, DLL). - ...by Arthur Pires +- cmake: CMake build to get started on non-Unix-like platforms, especially + for just libmpg123 on Windows - Sony PSP: Sony_PSP/; building libmpg123 for the PSP (used for the MODO player). ...by Bastian Pflieger -- Xcode contains the project file for building and using libmpg123 with - Xcode for Mac and iOS (arm and simulator builds). Please add the - ports/Xcode folder to the header search path of your project so that - Xcode can find the right mpg123.h and config.h. Then drag the mpg123 - Xcode project into your own project. Finally in your build target, build - phases, add mpg123-ios or mpg123-mac to the libraries to link. diff --git a/ports/cmake/linux_i686.toolchain.cmake b/ports/cmake/linux_i686.toolchain.cmake new file mode 100644 index 0000000..d33184e --- /dev/null +++ b/ports/cmake/linux_i686.toolchain.cmake @@ -0,0 +1,7 @@ + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR "i686") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32" CACHE STRING "c flags") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -m32" CACHE STRING "asm flags") diff --git a/ports/cmake/src/CMakeLists.txt b/ports/cmake/src/CMakeLists.txt index 44f99b9..5066ee3 100644 --- a/ports/cmake/src/CMakeLists.txt +++ b/ports/cmake/src/CMakeLists.txt @@ -8,20 +8,25 @@ include(CheckSymbolExists) include(CMakeDependentOption) include(TestBigEndian) +check_include_file("arpa/inet.h" HAVE_ARPA_INET_H) check_include_file("dirent.h" HAVE_DIRENT_H) check_include_file("dlfcn.h" HAVE_DLFCN_H) check_include_file("inttypes.h" HAVE_INTTYPES_H) check_include_file("langinfo.h" HAVE_LANGINFO_H) check_include_file("limits.h" HAVE_LIMITS_H) check_include_file("locale.h" HAVE_LOCALE_H) +check_include_file("netdb.h" HAVE_NETDB_H) +check_include_file("netinet/in.h" HAVE_NETINET_IN_H) check_include_file("sched.h" HAVE_SCHED_H) check_include_file("signal.h" HAVE_SIGNAL_H) check_include_file("stdio.h" HAVE_STDIO_H) check_include_file("stdint.h" HAVE_STDINT_H) check_include_file("stdlib.h" HAVE_STDLIB_H) check_include_file("string.h" HAVE_STRING_H) +check_include_file("strings.h" HAVE_STRINGS_H) check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H) check_include_file("sys/ipc.h" HAVE_SYS_IPC_H) +check_include_file("sys/param.h" HAVE_SYS_PARAM_H) check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H) check_include_file("sys/select.h" HAVE_SYS_SELECT_H) check_include_file("sys/shm.h" HAVE_SYS_SHM_H) @@ -46,6 +51,8 @@ check_function_exists(mkfifo HAVE_MKFIFO) check_function_exists(mmap HAVE_MMAP) check_function_exists(nl_langinfo HAVE_NL_LANGINFO) check_function_exists(random HAVE_RANDOM) +check_function_exists(setenv HAVE_SETENV) +check_function_exists(unsetenv HAVE_UNSETENV) check_function_exists(setlocale HAVE_SETLOCALE) check_function_exists(setpriority HAVE_SETPRIORITY) check_function_exists(shmget HAVE_SHMGET) @@ -173,6 +180,10 @@ if(WIN32) set(HAVE_MKFIFO ON) endif() +if(HAVE_NETDB_H AND HAVE_SYS_PARAM_H AND HAVE_SYS_SOCKET_H AND HAVE_NETINET_IN_H AND HAVE_ARPA_INET_H) + set(HAVE_NETWORK ON) +endif() + if(NO_MESSAGES) set(NO_WARNING ON) set(NO_ERRORMSG ON) @@ -313,6 +324,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -pedantic") endif() endif() +cmake_dependent_option(NETWORK "network support (http streams / webradio)" ON "HAVE_NETWORK" OFF) option(NEWOLD_WRITE_SAMPLE "enable new/old WRITE_SAMPLE macro for non-accurate 16 bit output, faster on certain CPUs (default on on x86-32)" OFF) cmake_dependent_option(NO_BUFFER "enable audio buffer code (default uses system whitelist... proper checks later)" OFF "HAVE_MMAP OR HAVE_SYS_IPC_H AND HAVE_SYS_SHM_H AND HAVE_SHMGET AND HAVE_SHMAT AND HAVE_SHMDT AND HAVE_SHMCTL" ON) option(NO_DOWNSAMPLE "no downsampled decoding" OFF) @@ -342,7 +354,6 @@ option(SYN123_NO_CASES "include special cases for likely parameter values (chann cmake_dependent_option(USE_MODULES "dynamically loadable output modules" ON "BUILD_SHARED_LIBS;HAVE_WIN_DL OR HAVE_UNIX_DL" OFF) option(USE_NEW_HUFFTABLE "use new huffman decoding scheme by Taihei (faster on modern CPUs at least, so on by default)" ON) -configure_file(config.cmake.h.in config.h) include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../../src/" @@ -370,7 +381,7 @@ if(UNIX) if(BUILD_PROGRAMS) - if(HAVE_FORK AND HAVE_EXECVP) + if(HAVE_FORK AND HAVE_EXECVP AND NETWORK) set(NET123 ON) set(NET123_EXEC ON) endif() @@ -449,3 +460,5 @@ if(UNIX) RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/") endif() endif() + +configure_file(config.cmake.h.in config.h) diff --git a/ports/cmake/src/config.cmake.h.in b/ports/cmake/src/config.cmake.h.in index 27dc92a..1af4958 100644 --- a/ports/cmake/src/config.cmake.h.in +++ b/ports/cmake/src/config.cmake.h.in @@ -43,6 +43,7 @@ #cmakedefine HAVE_STDLIB_H 1 #cmakedefine HAVE_STRERROR 1 #cmakedefine HAVE_STRING_H 1 +#cmakedefine HAVE_STRINGS_H 1 #cmakedefine HAVE_SYS_IOCTL_H 1 #cmakedefine HAVE_SYS_RESOURCE_H 1 #cmakedefine HAVE_SYS_SELECT_H 1 @@ -69,9 +70,13 @@ #define LFS_ALIAS_BITS @LFS_ALIAS_BITS@ #define LT_MODULE_EXT "@CMAKE_SHARED_MODULE_SUFFIX@" +// Define if network support is enabled. +#cmakedefine NETWORK 1 // Define for new-style network code. #cmakedefine NET123 1 -#cmakedefine +#cmakedefine NET123_EXEC 1 +#cmakedefine NET123_WINHTTP 1 +#cmakedefine NET123_WININET 1 // Define to disable downsampled decoding. #cmakedefine NO_DOWNSAMPLE 1 diff --git a/ports/cmake/src/libmpg123/CMakeLists.txt b/ports/cmake/src/libmpg123/CMakeLists.txt index 9305452..9f0f75a 100644 --- a/ports/cmake/src/libmpg123/CMakeLists.txt +++ b/ports/cmake/src/libmpg123/CMakeLists.txt @@ -214,6 +214,9 @@ endif() set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME mpg123) +target_compile_definitions(${TARGET} PRIVATE + $<$>:PIC>) + target_compile_definitions(${TARGET} PRIVATE ${PLATFORM_DEFINITIONS} $<$:REAL_IS_FLOAT> diff --git a/src/Makemodule.am b/src/Makemodule.am index 7b30217..9946fbc 100644 --- a/src/Makemodule.am +++ b/src/Makemodule.am @@ -118,17 +118,21 @@ if TERM_NONE src_mpg123_SOURCES += src/term_none.c endif +if NET123 +src_mpg123_SOURCES += src/net123.h +endif + if NET123_EXEC -src_mpg123_SOURCES += src/net123.h src/net123_exec.c +src_mpg123_SOURCES += src/net123_exec.c endif if NET123_WINHTTP -src_mpg123_SOURCES += src/net123.h src/net123_winhttp.c +src_mpg123_SOURCES += src/net123_winhttp.c src_mpg123_LDADD += -lwinhttp endif if NET123_WININET -src_mpg123_SOURCES += src/net123.h src/net123_wininet.c +src_mpg123_SOURCES += src/net123_wininet.c src_mpg123_LDADD += -lwininet endif diff --git a/src/common.c b/src/common.c index ce7f438..0ba12ab 100644 --- a/src/common.c +++ b/src/common.c @@ -179,7 +179,6 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar off_t rframes; int spf; double basevol, realvol; - char *icy; long rate; int framesize; struct mpg123_frameinfo mi; @@ -222,7 +221,8 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar /* Some sensible logic around offsets and time. Buffering makes the relationships between the numbers non-trivial. */ rframes = frames-frame; - elapsed = decoded + offset*spf - buffered; /* May be negative, a countdown. */ + // May be negative, a countdown. Buffer only confuses in paused (looping) mode, though. + elapsed = decoded + offset*spf - (paused ? 0 : buffered); remain = elapsed > 0 ? length - elapsed : length; if( MPG123_OK == mpg123_info(fr, &mi) && MPG123_OK == mpg123_getvolume(fr, &basevol, &realvol, NULL) ) diff --git a/src/config.h.in b/src/config.h.in index 3fed0dc..f4c980d 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -187,6 +187,9 @@ /* Define to 1 if you have the `sched_setscheduler' function. */ #undef HAVE_SCHED_SETSCHEDULER +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + /* Define to 1 if you have the `setlocale' function. */ #undef HAVE_SETLOCALE @@ -214,9 +217,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H -/* Define to 1 if you have the header file. */ -#undef HAVE_SNDIO_H - /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H @@ -289,6 +289,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `unsetenv' function. */ +#undef HAVE_UNSETENV + /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H @@ -301,6 +304,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_WCTYPE_H +/* Define to 1 if you have the header file. */ +#undef HAVE_WINCON_H + /* Define to 1 if you have the header file. */ #undef HAVE_WINDOWS_H @@ -338,6 +344,15 @@ /* Define to for new net123 network stack. */ #undef NET123 +/* Define for executable-based networking (for HTTPS). */ +#undef NET123_EXEC + +/* Define for winhttp networking (for HTTPS). */ +#undef NET123_WINHTTP + +/* Define for wininet networking (for HTTPS). */ +#undef NET123_WININET + /* Define if network support is enabled. */ #undef NETWORK diff --git a/src/control_generic.c b/src/control_generic.c index 5a75921..1eb2dd3 100644 --- a/src/control_generic.c +++ b/src/control_generic.c @@ -435,6 +435,10 @@ int control_generic (mpg123_handle *fr) } #endif + // Persist over loop iterations to remember unfinished commands. + char buf[REMOTE_BUFFER_SIZE]; // command buffer + short int last_len = 0; // length of partial command in there + while (alive) { tv.tv_sec = 0; @@ -510,16 +514,15 @@ int control_generic (mpg123_handle *fr) short int len = 1; /* length of buffer */ char *cmd, *arg; /* variables for parsing, */ char *comstr = NULL; /* gcc thinks that this could be used uninitialited... */ - char buf[REMOTE_BUFFER_SIZE]; short int counter; char *next_comstr = buf; /* have it initialized for first command */ /* read as much as possible, maybe multiple commands */ /* When there is nothing to read (EOF) or even an error, it is the end */ #ifdef WANT_WIN32_FIFO - len = win32_fifo_read(buf,REMOTE_BUFFER_SIZE); + len = win32_fifo_read(buf+last_len,REMOTE_BUFFER_SIZE-last_len); #else - len = read(control_file, buf, REMOTE_BUFFER_SIZE); + len = read(control_file, buf+last_len, REMOTE_BUFFER_SIZE-last_len); #endif if(len < 1) { @@ -542,7 +545,9 @@ int control_generic (mpg123_handle *fr) } debug1("read %i bytes of commands", len); + len += last_len; // on top of remembered piece /* one command on a line - separation by \n -> C strings in a row */ + last_len = 0; for(counter = 0; counter < len; ++counter) { /* line end is command end */ @@ -746,7 +751,6 @@ int control_generic (mpg123_handle *fr) /* Simple EQ: SEQ */ if (!strcasecmp(cmd, "SEQ")) { double b,m,t; - int cn; if(sscanf(arg, "%lf %lf %lf", &b, &m, &t) == 3) { mpg123_eq_bands(fr, MPG123_LR, 0, 0, b); @@ -891,7 +895,7 @@ int control_generic (mpg123_handle *fr) if (!strcasecmp(cmd, "LP") || !strcasecmp(cmd, "LOADPAUSED")){ generic_load(fr, arg, MODE_PAUSED); continue; } /* no command matched */ - generic_sendstr(0, "E Unknown command: %s", cmd); + generic_send2str(0, "E Unknown command with arguments: %s %s", cmd, arg); } /* end commands with arguments */ else generic_sendstr( 0, "E Unknown command or no arguments: %s" , comstr ); @@ -899,30 +903,19 @@ int control_generic (mpg123_handle *fr) } /* end of single command processing */ } /* end of scanning the command buffer */ - /* - when last command had no \n... should I discard it? - Ideally, I should remember the part and wait for next - read() to get the rest up to a \n. But that can go - to infinity. Too long commands too quickly are just - bad. Cannot/Won't change that. So, discard the unfinished - command and have fingers crossed that the rest of this - unfinished one qualifies as "unknown". - */ + // Last character not nulled if we did not use all command text. if(buf[len-1] != 0) { - // All that jazz because I did not reserve space for a zero. - char *last_command; - size_t last_len = len-(size_t)(next_comstr-buf); - last_command = malloc(last_len+1); - if(last_command) + if(next_comstr == buf && len == REMOTE_BUFFER_SIZE) { - memcpy(last_command, next_comstr, last_len); - last_command[last_len] = 0; - generic_sendstr(0, "E Unfinished command: %s", last_command); - free(last_command); + generic_sendmsg("E Too long command, cannot parse."); + // Just skipping it, provoking further parsing erros, but maybe not fatal. + } else + { + last_len = len-(short)(next_comstr-buf); + mdebug("keeping %d bytes of old command", last_len); + memmove(buf, next_comstr, last_len); } - else - generic_sendmsg("E Unfinished command: "); } } /* end command reading & processing */ } /* end main (alive) loop */ diff --git a/src/getlopt.c b/src/getlopt.c index 305d433..ac1a55b 100644 --- a/src/getlopt.c +++ b/src/getlopt.c @@ -106,15 +106,29 @@ static int performoption (int argc, char *argv[], topt *opt, topt *opts) return (GLO_NOARG); loptarg = argv[loptind++]+loptchr; loptchr = 0; + errno = 0; if (opt->var) { + char *endptr = NULL; if (opt->flags & GLO_CHAR) /* var is *char */ setcharoption(opt, loptarg); - else if(opt->flags & GLO_LONG) - *((long *) opt->var) = atol(loptarg); - else if(opt->flags & GLO_INT) - *((int *) opt->var) = atoi(loptarg); + else if(opt->flags & (GLO_LONG | GLO_INT)) + { + long val = strtol(loptarg, &endptr, 10); + if(errno || endptr == loptarg || (endptr && *endptr)) + return GLO_BADARG; + if(opt->flags & GLO_LONG) + *((long *) opt->var) = val; + else if(val <= INT_MAX && val >= INT_MIN) + *((int *) opt->var) = val; + else + return GLO_BADARG; + } else if(opt->flags & GLO_DOUBLE) - *((double *) opt->var) = atof(loptarg); + { + *((double *) opt->var) = strtod(loptarg, &endptr); + if(errno || endptr == loptarg || (endptr && *endptr)) + return GLO_BADARG; + } else prog_error(); } #if 0 /* Oliver: What was this for?! --ThOr */ diff --git a/src/getlopt.h b/src/getlopt.h index 85014b6..b3696f1 100644 --- a/src/getlopt.h +++ b/src/getlopt.h @@ -66,6 +66,7 @@ for .... no flag) */ #define GLO_UNKNOWN -1 #define GLO_NOARG -2 #define GLO_CONTINUE -3 +#define GLO_BADARG -4 int getlopt (int argc, char *argv[], topt *opts); // Helper to set a char parameter, avoiding memory leaks. diff --git a/src/httpget.c b/src/httpget.c index 6026fdf..cb4741f 100644 --- a/src/httpget.c +++ b/src/httpget.c @@ -153,74 +153,6 @@ debunk_result: #ifdef NETWORK -#if !defined (WANT_WIN32_SOCKETS) -static int writestring (int fd, mpg123_string *string) -{ - size_t result, bytes; - char *ptr = string->p; - bytes = string->fill ? string->fill-1 : 0; - - while(bytes) - { - result = write(fd, ptr, bytes); - if(result < 0 && errno != EINTR) - { - merror("writing http string: %s", strerror(errno)); - return FALSE; - } - else if(result == 0) - { - error("write: socket closed unexpectedly"); - return FALSE; - } - ptr += result; - bytes -= result; - } - return TRUE; -} - -static size_t readstring (mpg123_string *string, size_t maxlen, int fd) -{ - int err; - debug2("Attempting readstring on %d for %"SIZE_P" bytes", fd, (size_p)maxlen); - string->fill = 0; - while(maxlen == 0 || string->fill < maxlen) - { - if(string->size-string->fill < 1) - if(!mpg123_grow_string(string, string->fill+4096)) - { - error("Cannot allocate memory for reading."); - string->fill = 0; - return 0; - } - err = read(fd,string->p+string->fill,1); - /* Whoa... reading one byte at a time... one could ensure the line break in another way, but more work. */ - if( err == 1) - { - string->fill++; - if(string->p[string->fill-1] == '\n') break; - } - else if(errno != EINTR) - { - error("Error reading from socket or unexpected EOF."); - string->fill = 0; - /* bail out to prevent endless loop */ - return 0; - } - } - - if(!mpg123_grow_string(string, string->fill+1)) - { - string->fill=0; - } - else - { - string->p[string->fill] = 0; - string->fill++; - } - return string->fill; -} -#endif /* WANT_WIN32_SOCKETS */ void encode64 (char *source,char *destination) { @@ -383,11 +315,10 @@ int translate_url(const char *url, mpg123_string *purl) return TRUE; } -int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *port, mpg123_string *httpauth1, int *try_without_port) +int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *port, mpg123_string *httpauth1, const char * const *client_head) { char* ttemp; int ret = TRUE; - const char *icy = param.talk_icy ? icy_yes : icy_no; /* hm, my test redirection had troubles with line break before HTTP/1.0 */ if((ttemp = strchr(request->p,'\r')) != NULL){ *ttemp = 0; request->fill = ttemp-request->p+1; } @@ -405,26 +336,14 @@ int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *por if(host->fill) { /* Give virtual hosting a chance... adding the "Host: ... " line. */ debug2("Host: %s:%s", host->p, port->p); - if( mpg123_add_string(request, "Host: ") + if(!( mpg123_add_string(request, "Host: ") && mpg123_add_string(request, host->p) - && ( *try_without_port || ( - mpg123_add_string(request, ":") - && mpg123_add_string(request, port->p) )) - && mpg123_add_string(request, "\r\n") ) - { - if(*try_without_port) *try_without_port = 0; - } - else return FALSE; + && mpg123_add_string(request, ":") + && mpg123_add_string(request, port->p) + && mpg123_add_string(request, "\r\n") )) + return FALSE; } - /* Acceptance, stream setup. */ - if( !append_accept(request) - || !mpg123_add_string(request, "\r\n") - || !mpg123_add_string(request, CONN_HEAD) - || !mpg123_add_string(request, icy) - || !mpg123_add_string(request, "\r\n") ) - return FALSE; - /* Authorization. */ if (httpauth1->fill || param.httpauth) { char *buf; @@ -456,72 +375,30 @@ int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *por free(buf); /* Watch out for leaking if you introduce returns before this line. */ } + while(ret && *client_head) + { + ret = mpg123_add_string(request, *client_head); + if(ret) + ret = mpg123_add_string(request, "\r\n"); + ++client_head; + } if(ret) ret = mpg123_add_string(request, "\r\n"); return ret; } -#if !defined (WANT_WIN32_SOCKETS) -static int resolve_redirect(mpg123_string *response, mpg123_string *request_url, mpg123_string *purl) -{ - debug1("request_url:%s", request_url->p); - /* initialized with full old url */ - if(!mpg123_copy_string(request_url, purl)) return FALSE; - /* We may strip it down to a prefix ot totally. */ - if(strncasecmp(response->p, "Location: http://", 17)) - { /* OK, only partial strip, need prefix for relative path. */ - char* ptmp = NULL; - /* though it's not RFC (?), accept relative URIs as wget does */ - fprintf(stderr, "NOTE: no complete URL in redirect, constructing one\n"); - /* not absolute uri, could still be server-absolute */ - /* I prepend a part of the request... out of the request */ - if(response->p[10] == '/') - { - /* only prepend http://server/ */ - /* I null the first / after http:// */ - ptmp = strchr(purl->p+7,'/'); - if(ptmp != NULL){ purl->fill = ptmp-purl->p+1; purl->p[purl->fill-1] = 0; } - } - else - { - /* prepend http://server/path/ */ - /* now we want the last / */ - ptmp = strrchr(purl->p+7, '/'); - if(ptmp != NULL){ purl->fill = ptmp-purl->p+2; purl->p[purl->fill-1] = 0; } - } - } - else purl->fill = 0; - - debug1("prefix=%s", purl->fill ? purl->p : ""); - if(!mpg123_add_string(purl, response->p+10)) return FALSE; - - debug1(" purl: %s", purl->p); - debug1("old request_url: %s", request_url->p); - - return TRUE; -} - -int http_open(const char* url, struct httpdata *hd) +int http_open(const char* url, struct httpdata *hd, const char * const *client_head) { mpg123_string purl, host, port, path; - mpg123_string request, response, request_url; + mpg123_string request, request_url; mpg123_string httpauth1; int sock = -1; int oom = 0; - int relocate, numrelocs = 0; - int got_location = FALSE; - /* - workaround for http://www.global24music.com/rautemusik/files/extreme/isdn.pls - this site's apache gives me a relocation to the same place when I give the port in Host request field - for the record: Apache/2.0.51 (Fedora) - */ - int try_without_port = 0; mpg123_init_string(&purl); mpg123_init_string(&host); mpg123_init_string(&port); mpg123_init_string(&path); mpg123_init_string(&request); - mpg123_init_string(&response); mpg123_init_string(&request_url); mpg123_init_string(&httpauth1); @@ -533,26 +410,6 @@ int http_open(const char* url, struct httpdata *hd) /* Don't confuse the different auth strings... */ if(!split_url(&purl, &httpauth1, NULL, NULL, NULL) ){ oom=1; goto exit; } - /* "GET http://" 11 - * " HTTP/1.0\r\nUser-Agent: /\r\n" - * 26 + PACKAGE_NAME + PACKAGE_VERSION - * accept header + accept_length() - * "Authorization: Basic \r\n" 23 - * "\r\n" 2 - * ... plus the other predefined header lines - */ - /* Just use this estimate as first guess to reduce malloc calls in string library. */ - { - size_t length_estimate = 62 + strlen(PACKAGE_NAME) + strlen(PACKAGE_VERSION) - + accept_length() + strlen(CONN_HEAD) + strlen(icy_yes) + purl.fill; - if( !mpg123_grow_string(&request, length_estimate) - || !mpg123_grow_string(&response,4096) ) - { - oom=1; goto exit; - } - } - - do { /* Storing the request url, with http:// prepended if needed. */ /* used to be url here... seemed wrong to me (when loop advanced...) */ @@ -585,7 +442,7 @@ int http_open(const char* url, struct httpdata *hd) } } - if(!fill_request(&request, &host, &port, &httpauth1, &try_without_port)){ oom=1; goto exit; } + if(!fill_request(&request, &host, &port, &httpauth1, client_head)){ oom=1; goto exit; } httpauth1.fill = 0; /* We use the auth data from the URL only once. */ if (hd->proxystate >= PROXY_HOST) @@ -599,105 +456,27 @@ int http_open(const char* url, struct httpdata *hd) } } debug2("attempting to open_connection to %s:%s", host.p, port.p); +#ifdef WANT_WIN32_SOCKETS + sock = win32_net_open_connection(&host, &port); +#else sock = open_connection(&host, &port); +#endif if(sock < 0) { error1("Unable to establish connection to %s", host.fill ? host.p : ""); goto exit; } #define http_failure close(sock); sock=-1; goto exit; - + if(param.verbose > 2) fprintf(stderr, "HTTP request:\n%s\n",request.p); - if(!writestring(sock, &request)){ http_failure; } - relocate = FALSE; - /* Arbitrary length limit here... */ -#define safe_readstring \ - readstring(&response, SIZE_MAX/16, sock); \ - if(response.fill > SIZE_MAX/16) /* > because of appended zero. */ \ - { \ - error("HTTP response line exceeds max. length"); \ - http_failure; \ - } \ - else if(response.fill == 0) \ - { \ - error("readstring failed"); \ - http_failure; \ - } \ - if(param.verbose > 2) fprintf(stderr, "HTTP in: %s", response.p); - safe_readstring; - +#ifdef WANT_WIN32_SOCKETS + if(!win32_net_writestring (sock, &request)) +#else + if(unintr_write(sock, request.p, request.fill-1) != request.fill-1) +#endif { - char *sptr; - if((sptr = strchr(response.p, ' '))) - { - if(response.fill > sptr-response.p+2) - switch (sptr[1]) - { - case '3': - relocate = TRUE; - case '2': - break; - default: - fprintf (stderr, "HTTP request failed: %s", sptr+1); /* '\n' is included */ - http_failure; - } - else{ error("Too short response,"); http_failure; } - } + http_failure; } - - /* If we are relocated, we need to look out for a Location header. */ - got_location = FALSE; - - do - { - safe_readstring; /* Think about that: Should we really error out when we get nothing? Could be that the server forgot the trailing empty line... */ - if (!strncasecmp(response.p, "Location: ", 10)) - { /* It is a redirection! */ - if(!resolve_redirect(&response, &request_url, &purl)){ oom=1, http_failure; } - - if(!strcmp(purl.p, request_url.p)) - { - warning("relocated to very same place! trying request again without host port"); - try_without_port = 1; - } - got_location = TRUE; - } - else - { /* We got a header line (or the closing empty line). */ - char *tmp; - debug1("searching for header values... %s", response.p); - /* Not sure if I want to bail out on error here. */ - /* Also: What text encoding are these strings in? Doesn't need to be plain ASCII... */ - get_header_string(&response, "content-type", &hd->content_type); - get_header_string(&response, "icy-name", &hd->icy_name); - get_header_string(&response, "icy-url", &hd->icy_url); - - /* watch out for icy-metaint */ - if((tmp = get_header_val("icy-metaint", &response))) - { - hd->icy_interval = (off_t) atol(tmp); /* atoll ? */ - debug1("got icy-metaint %li", (long int)hd->icy_interval); - } - } - } while(response.p[0] != '\r' && response.p[0] != '\n'); - if(relocate) - { - close(sock); - sock = -1; - /* Forget content type, might just relate to a displayed error page, - not the resource being redirected to. */ - mpg123_free_string(&hd->content_type); - mpg123_init_string(&hd->content_type); - } - } while(relocate && got_location && purl.fill && numrelocs++ < HTTP_MAX_RELOCATIONS); - if(relocate) - { - if(!got_location) - error("Server meant to redirect but failed to provide a location!"); - else - error1("Too many HTTP relocations (%i).", numrelocs); - - http_failure; } exit: /* The end as well as the exception handling point... */ @@ -708,22 +487,10 @@ exit: /* The end as well as the exception handling point... */ mpg123_free_string(&port); mpg123_free_string(&path); mpg123_free_string(&request); - mpg123_free_string(&response); mpg123_free_string(&request_url); mpg123_free_string(&httpauth1); return sock; } -#endif /*WANT_WIN32_SOCKETS*/ - -#else /* NETWORK */ - -/* stub */ -int http_open (const char* url, struct httpdata *hd) -{ - if(!param.quiet) - error("HTTP support not built in."); - return -1; -} #endif /* EOF */ diff --git a/src/httpget.h b/src/httpget.h index ecdb80b..4805c53 100644 --- a/src/httpget.h +++ b/src/httpget.h @@ -49,20 +49,17 @@ int debunk_mime(const char* mime); int proxy_init(struct httpdata *hd); int translate_url(const char *url, mpg123_string *purl); size_t accept_length(void); -int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *port, mpg123_string *httpauth1, int *try_without_port); +int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *port, mpg123_string *httpauth1, const char * const *client_head); void get_header_string(mpg123_string *response, const char *fieldname, mpg123_string *store); char *get_header_val(const char *hname, mpg123_string *response); -/* needed for HTTP/1.1 non-pipelining mode */ -/* #define CONN_HEAD "Connection: close\r\n" */ -#define CONN_HEAD "" #define icy_yes "Icy-MetaData: 1" #define icy_no "Icy-MetaData: 0" // Append an accept header line to the string, without line end. int append_accept(mpg123_string *s); -/* takes url and content type string address, opens resource, returns fd for data, allocates and sets content type */ -extern int http_open (const char* url, struct httpdata *hd); +// Open HTTP URL with internal network code. +int http_open(const char* url, struct httpdata *hd, const char * const *client_head); #endif diff --git a/src/intsym.h b/src/intsym.h index 7c817e3..cc975d4 100644 --- a/src/intsym.h +++ b/src/intsym.h @@ -16,6 +16,7 @@ #define compat_fdopen INT123_compat_fdopen #define compat_close INT123_compat_close #define compat_fclose INT123_compat_fclose +#define compat_binmode INT123_compat_binmode #define win32_wide_utf8 INT123_win32_wide_utf8 #define win32_wide_utf7 INT123_win32_wide_utf7 #define win32_utf8_wide INT123_win32_utf8_wide @@ -277,9 +278,6 @@ #define buffer_drop INT123_buffer_drop #define buffer_write INT123_buffer_write #define buffer_fill INT123_buffer_fill -#define read_buf INT123_read_buf -#define xfer_write_string INT123_xfer_write_string -#define xfer_read_string INT123_xfer_read_string #define xfermem_init INT123_xfermem_init #define xfermem_init_writer INT123_xfermem_init_writer #define xfermem_init_reader INT123_xfermem_init_reader @@ -304,8 +302,6 @@ #define raw_formats INT123_raw_formats #define wav_formats INT123_wav_formats #define wav_drain INT123_wav_drain -#define write_parameters INT123_write_parameters -#define read_parameters INT123_read_parameters #define stringlists_add INT123_stringlists_add #define check_neon INT123_check_neon #define dct64_3dnow INT123_dct64_3dnow diff --git a/src/libmpg123/dct36_3dnow.S b/src/libmpg123/dct36_3dnow.S index 2d45dc0..9b0222d 100644 --- a/src/libmpg123/dct36_3dnow.S +++ b/src/libmpg123/dct36_3dnow.S @@ -35,7 +35,9 @@ ASM_NAME(dct36_3dnow): pushl %ebp movl %esp,%ebp -#if defined(PIC) && defined(__APPLE__) +// Not entirely sure about this PIC_GLOBAL_PTR here, but this is highly +// irrelevant, anyway. Anyone building 3DNow code for Android or Apple systems? +#ifdef PIC_GLOBAL_PTR sub $4,%esp #endif pushl %esi @@ -45,7 +47,7 @@ ASM_NAME(dct36_3dnow): #define _EBX_ %edi PREPARE_GOT GET_GOT -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR #define _COS9_ 0(%edi) #define _tfcos36_ 0(%eax) mov GLOBAL_VAR_PTR(tfcos36), %eax @@ -187,7 +189,7 @@ ASM_NAME(dct36_3dnow): movq %mm2,%mm4 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 0+_tfcos36_,%mm5 @@ -217,7 +219,7 @@ ASM_NAME(dct36_3dnow): pfsub %mm2,%mm4 movq %mm7,%mm5 punpckldq 32+_tfcos36_,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov 8(%ebp),%eax #endif pfmul %mm5,%mm4 @@ -265,7 +267,7 @@ ASM_NAME(dct36_3dnow): movq %mm2,%mm4 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 4+_tfcos36_,%mm5 @@ -295,7 +297,7 @@ ASM_NAME(dct36_3dnow): pfsub %mm2,%mm4 movq %mm7,%mm5 punpckldq 28+_tfcos36_,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov 8(%ebp),%eax #endif pfmul %mm5,%mm4 @@ -356,7 +358,7 @@ ASM_NAME(dct36_3dnow): movq %mm2,%mm4 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 8+_tfcos36_,%mm5 @@ -386,7 +388,7 @@ ASM_NAME(dct36_3dnow): pfsub %mm2,%mm4 movq %mm7,%mm5 punpckldq 24+_tfcos36_,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov 8(%ebp),%eax #endif pfmul %mm5,%mm4 @@ -446,7 +448,7 @@ ASM_NAME(dct36_3dnow): movq %mm2,%mm4 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 12+_tfcos36_,%mm5 @@ -476,7 +478,7 @@ ASM_NAME(dct36_3dnow): pfsub %mm2,%mm4 movq %mm7,%mm5 punpckldq 20+_tfcos36_,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov 8(%ebp),%eax #endif pfmul %mm5,%mm4 @@ -512,7 +514,7 @@ ASM_NAME(dct36_3dnow): movq 64(%eax),%mm3 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 16+_tfcos36_,%mm5 diff --git a/src/libmpg123/dct36_3dnowext.S b/src/libmpg123/dct36_3dnowext.S index 287b6b9..fb95d43 100644 --- a/src/libmpg123/dct36_3dnowext.S +++ b/src/libmpg123/dct36_3dnowext.S @@ -48,7 +48,9 @@ ASM_NAME(dct36_3dnowext): pushl %ebp movl %esp, %ebp -#if defined(PIC) && defined(__APPLE__) +// Not entirely sure about this PIC_GLOBAL_PTR here, but this is highly +// irrelevant, anyway. Anyone building 3DNow code for Android or Apple systems? +#ifdef PIC_GLOBAL_PTR sub $4, %esp #endif pushl %esi @@ -58,7 +60,7 @@ ASM_NAME(dct36_3dnowext): #define _EBX_ %edi PREPARE_GOT GET_GOT -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR #define _COS9_ 0(%edi) #define _tfcos36_ 0(%eax) mov GLOBAL_VAR_PTR(tfcos36), %eax @@ -198,7 +200,7 @@ ASM_NAME(dct36_3dnowext): movq %mm2,%mm4 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 0+_tfcos36_,%mm5 @@ -227,7 +229,7 @@ ASM_NAME(dct36_3dnowext): pfsub %mm2,%mm4 movq %mm7,%mm5 punpckldq 32+_tfcos36_,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov 8(%ebp),%eax #endif pfmul %mm5,%mm4 @@ -275,7 +277,7 @@ ASM_NAME(dct36_3dnowext): movq %mm2,%mm4 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 4+_tfcos36_,%mm5 @@ -305,7 +307,7 @@ ASM_NAME(dct36_3dnowext): pfsub %mm2,%mm4 movq %mm7,%mm5 punpckldq 28+_tfcos36_,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov 8(%ebp),%eax #endif pfmul %mm5,%mm4 @@ -365,7 +367,7 @@ ASM_NAME(dct36_3dnowext): movq %mm2,%mm4 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 8+_tfcos36_,%mm5 @@ -395,7 +397,7 @@ ASM_NAME(dct36_3dnowext): pfsub %mm2,%mm4 movq %mm7,%mm5 punpckldq 24+_tfcos36_,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov 8(%ebp),%eax #endif pfmul %mm5,%mm4 @@ -455,7 +457,7 @@ ASM_NAME(dct36_3dnowext): movq %mm2,%mm4 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 12+_tfcos36_,%mm5 @@ -485,7 +487,7 @@ ASM_NAME(dct36_3dnowext): pfsub %mm2,%mm4 movq %mm7,%mm5 punpckldq 20+_tfcos36_,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov 8(%ebp),%eax #endif pfmul %mm5,%mm4 @@ -520,7 +522,7 @@ ASM_NAME(dct36_3dnowext): movq 64(%eax),%mm3 pfadd %mm3,%mm4 movq %mm7,%mm5 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov -4(%ebp),%eax #endif punpckldq 16+_tfcos36_,%mm5 diff --git a/src/libmpg123/dct64_3dnow.S b/src/libmpg123/dct64_3dnow.S index 99e6a2c..5265a87 100644 --- a/src/libmpg123/dct64_3dnow.S +++ b/src/libmpg123/dct64_3dnow.S @@ -36,7 +36,7 @@ ASM_NAME(dct64_3dnow): /* femms */ /* 1 */ -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR movl GLOBAL_VAR_PTR(pnts),%eax movl (%eax),%eax #else @@ -140,7 +140,7 @@ ASM_NAME(dct64_3dnow): movd %mm5,64(%ebx) /* 2 */ -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR movl GLOBAL_VAR_PTR(pnts),%eax movl 4(%eax),%eax #else @@ -248,7 +248,7 @@ ASM_NAME(dct64_3dnow): movd %mm5,96(%esi) /* 3 */ -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR movl GLOBAL_VAR_PTR(pnts),%eax movl 8(%eax),%eax #else @@ -354,7 +354,7 @@ ASM_NAME(dct64_3dnow): movd %mm6,112(%ebx) /* 4 */ -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR movl GLOBAL_VAR_PTR(pnts),%eax movl 12(%eax),%eax #else @@ -469,7 +469,7 @@ ASM_NAME(dct64_3dnow): pi2fd %mm0,%mm0 movd %eax,%mm1 pi2fd %mm1,%mm1 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR movl GLOBAL_VAR_PTR(pnts),%eax movl 16(%eax),%eax #else diff --git a/src/libmpg123/dct64_mmx.S b/src/libmpg123/dct64_mmx.S index ff8d403..95d426c 100644 --- a/src/libmpg123/dct64_mmx.S +++ b/src/libmpg123/dct64_mmx.S @@ -32,7 +32,7 @@ ASM_NAME(dct64_MMX): fstps (%edx) movl 276(%esp),%edi flds 4(%eax) -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR movl GLOBAL_VAR_PTR(costab_mmxsse),%ebx #else leal GLOBAL_VAR(costab_mmxsse),%ebx diff --git a/src/libmpg123/dct64_sse.S b/src/libmpg123/dct64_sse.S index 16bcd69..fd1802f 100644 --- a/src/libmpg123/dct64_sse.S +++ b/src/libmpg123/dct64_sse.S @@ -77,7 +77,7 @@ ASM_NAME(dct64_sse): subps %xmm0, %xmm5 subps %xmm1, %xmm4 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov GLOBAL_VAR_PTR(costab_mmxsse), %ecx #else lea GLOBAL_VAR(costab_mmxsse), %ecx diff --git a/src/libmpg123/dct64_sse_float.S b/src/libmpg123/dct64_sse_float.S index 544d2d6..1dbd0df 100644 --- a/src/libmpg123/dct64_sse_float.S +++ b/src/libmpg123/dct64_sse_float.S @@ -77,7 +77,7 @@ ASM_NAME(dct64_real_sse): subps %xmm0, %xmm5 subps %xmm1, %xmm4 -#if defined(PIC) && defined(__APPLE__) +#ifdef PIC_GLOBAL_PTR mov GLOBAL_VAR_PTR(costab_mmxsse), %eax #else lea GLOBAL_VAR(costab_mmxsse), %eax diff --git a/src/libmpg123/mangle.h b/src/libmpg123/mangle.h index e37386a..aaebfd3 100644 --- a/src/libmpg123/mangle.h +++ b/src/libmpg123/mangle.h @@ -139,6 +139,11 @@ Lpic_base: \ #endif /* PIC variants */ +// Apple and Android NDK seem both not to like direct global access. +#if defined(PIC) && (defined(__APPLE__) || defined(ANDROID)) +#define PIC_GLOBAL_PTR +#endif + #endif /* OPT_X86 */ #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__APPLE__) diff --git a/src/libout123/buffer.c b/src/libout123/buffer.c index 7030991..42a1d31 100644 --- a/src/libout123/buffer.c +++ b/src/libout123/buffer.c @@ -68,6 +68,9 @@ static void catch_interrupt (void) intflag = TRUE; } +static int xfer_write_string(out123_handle *ao, int who, const char *buf); +static int xfer_read_string(out123_handle *ao, int who, char **buf); +static int read_buf(int fd, void *addr, size_t size, byte *prebuf, int *preoff, int presize); static int read_record(out123_handle *ao , int who, void **buf, byte *prebuf, int *preoff, int presize, size_t *recsize); static int buffer_loop(out123_handle *ao); @@ -198,6 +201,47 @@ static int buffer_cmd_finish(out123_handle *ao) } } +/* Serialization of tunable parameters to communicate them between + main process and buffer. Make sure these two stay in sync ... */ + +static int write_parameters(out123_handle *ao, int who) +{ + int fd = ao->buffermem->fd[who]; + if( + GOOD_WRITEVAL(fd, ao->flags) + && GOOD_WRITEVAL(fd, ao->preload) + && GOOD_WRITEVAL(fd, ao->gain) + && GOOD_WRITEVAL(fd, ao->device_buffer) + && GOOD_WRITEVAL(fd, ao->verbose) + && !xfer_write_string(ao, who, ao->name) + && !xfer_write_string(ao, who, ao->bindir) + ) + return 0; + else + return -1; +} + +static int read_parameters(out123_handle *ao +, int who, byte *prebuf, int *preoff, int presize) +{ + int fd = ao->buffermem->fd[who]; +#define GOOD_READVAL_BUF(fd, val) \ + !read_buf(fd, &val, sizeof(val), prebuf, preoff, presize) + if( + GOOD_READVAL_BUF(fd, ao->flags) + && GOOD_READVAL_BUF(fd, ao->preload) + && GOOD_READVAL_BUF(fd, ao->gain) + && GOOD_READVAL_BUF(fd, ao->device_buffer) + && GOOD_READVAL_BUF(fd, ao->verbose) + && !read_record(ao, who, (void**)&ao->name, prebuf, preoff, presize, NULL) + && !read_record(ao, who, (void**)&ao->bindir, prebuf, preoff, presize, NULL) + ) + return 0; + else + return -1; +#undef GOOD_READVAL_BUF +} + int buffer_sync_param(out123_handle *ao) { int writerfd = ao->buffermem->fd[XF_WRITER]; @@ -524,7 +568,7 @@ int xfer_write_string(out123_handle *ao, int who, const char *buf) } -int xfer_read_string(out123_handle *ao, int who, char **buf) +static int xfer_read_string(out123_handle *ao, int who, char **buf) { /* ao->errcode set in read_record() */ return read_record(ao, who, (void**)buf, NULL, NULL, 0, NULL) @@ -536,7 +580,7 @@ int xfer_read_string(out123_handle *ao, int who, char **buf) This assumes responsible use and avoids needless checking of input. And, yes, it modifies the preoff argument! Returns 0 on success, modifies prebuffer fill. */ -int read_buf(int fd, void *addr, size_t size, byte *prebuf, int *preoff, int presize) +static int read_buf(int fd, void *addr, size_t size, byte *prebuf, int *preoff, int presize) { size_t need = size; diff --git a/src/libout123/buffer.h b/src/libout123/buffer.h index 455876c..d0780a1 100644 --- a/src/libout123/buffer.h +++ b/src/libout123/buffer.h @@ -54,13 +54,4 @@ size_t buffer_write(out123_handle *ao, void *buffer, size_t bytes); /* Thin wrapper over xfermem giving the current buffer fill. */ size_t buffer_fill(out123_handle *ao); -/* Special handler to safely read values from command channel with - an additional buffer handed in. Exported for read_parameters(). */ -int read_buf(int fd, void *addr, size_t size -, byte *prebuf, int *preoff, int presize); - -/* Read/write strings from/to command channel. 0 on success. */ -int xfer_write_string(out123_handle *ao, int who, const char *buf); -int xfer_read_string(out123_handle *ao, int who, char* *buf); - #endif diff --git a/src/libout123/libout123.c b/src/libout123/libout123.c index 289be42..178548f 100644 --- a/src/libout123/libout123.c +++ b/src/libout123/libout123.c @@ -361,49 +361,6 @@ out123_param_from(out123_handle *ao, out123_handle* from_ao) return 0; } -#ifndef NOXFERMEM -/* Serialization of tunable parameters to communicate them between - main process and buffer. Make sure these two stay in sync ... */ - -int write_parameters(out123_handle *ao, int who) -{ - int fd = ao->buffermem->fd[who]; - if( - GOOD_WRITEVAL(fd, ao->flags) - && GOOD_WRITEVAL(fd, ao->preload) - && GOOD_WRITEVAL(fd, ao->gain) - && GOOD_WRITEVAL(fd, ao->device_buffer) - && GOOD_WRITEVAL(fd, ao->verbose) - && !xfer_write_string(ao, who, ao->name) - && !xfer_write_string(ao, who, ao->bindir) - ) - return 0; - else - return -1; -} - -int read_parameters(out123_handle *ao -, int who, byte *prebuf, int *preoff, int presize) -{ - int fd = ao->buffermem->fd[who]; -#define GOOD_READVAL_BUF(fd, val) \ - !read_buf(fd, &val, sizeof(val), prebuf, preoff, presize) - if( - GOOD_READVAL_BUF(fd, ao->flags) - && GOOD_READVAL_BUF(fd, ao->preload) - && GOOD_READVAL_BUF(fd, ao->gain) - && GOOD_READVAL_BUF(fd, ao->device_buffer) - && GOOD_READVAL_BUF(fd, ao->verbose) - && !xfer_read_string(ao, who, &ao->name) - && !xfer_read_string(ao, who, &ao->bindir) - ) - return 0; - else - return -1; -#undef GOOD_READVAL_BUF -} -#endif - int attribute_align_arg out123_open(out123_handle *ao, const char* driver, const char* device) { @@ -730,8 +687,14 @@ out123_play(out123_handle *ao, void *bytes, size_t count) sum += written; count -= written; } - if(written < block && errno != EINTR) - { + if(written < block && errno != EINTR + && errno != EAGAIN +#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) + // Not all platforms define it (or only in more modern POSIX modes). + // Standard says it is supposed to be a macro, so simple check here. + && errno != EWOULDBLOCK +#endif + ){ ao->errcode = OUT123_DEV_PLAY; if(!AOQUIET) merror( "Error in writing audio, wrote only %d of %d (%s?)!" diff --git a/src/libout123/modules/win32.c b/src/libout123/modules/win32.c index 961d450..29c8a59 100644 --- a/src/libout123/modules/win32.c +++ b/src/libout123/modules/win32.c @@ -18,9 +18,16 @@ NOTE: This particular num/size combination performs best under heavy loads for my system, however this may not be true for any hardware/OS out there. Generally, BUFFER_SIZE < 8k || NUM_BUFFERS > 16 || NUM_BUFFERS < 4 are not recommended. + + Introducing user-settable device buffer. We fix 8 buffers, scale the individual + buffer size, rounded/truncated a bit to not be too odd. The old default of 64K + buffers leads to 2.97 s with CD-DA. Quite excessive. We will probably reduce this + soon. */ -#define BUFFER_SIZE 0x10000 -#define NUM_BUFFERS 8 /* total 512k roughly 2.5 sec of CD quality sound */ +#define DEFAULT_DEVICE_BUFFER 0.25 +// Buffers are multiples of this. +#define BUFFER_GRANULARITY 256 +#define NUM_BUFFERS 8 static void wait_for_buffer(WAVEHDR* hdr, HANDLE hEvent); static void drain_win32(out123_handle *ao); @@ -29,6 +36,7 @@ static void drain_win32(out123_handle *ao); struct queue_state { WAVEHDR buffer_headers[NUM_BUFFERS]; + size_t bufsize; /* The next buffer to be filled and put in playback */ int next_buffer; /* Buffer playback completion event */ @@ -100,11 +108,18 @@ static int open_win32(out123_handle *ao) ereturn(-1, "Unable to open wave output device."); } + state->bufsize = (size_t)( (double) + (ao->device_buffer > 0. ? ao->device_buffer : DEFAULT_DEVICE_BUFFER) + * out_fmt.nAvgBytesPerSec / NUM_BUFFERS / BUFFER_GRANULARITY); + if(state->bufsize < 1) + state->bufsize = 1; + state->bufsize *= BUFFER_GRANULARITY; + /* Reset event from the "device open" message */ ResetEvent(state->play_done_event); /* Allocate playback buffers */ for(i = 0; i < NUM_BUFFERS; i++) - if(!(state->buffer_headers[i].lpData = (LPSTR)malloc(BUFFER_SIZE))) + if(!(state->buffer_headers[i].lpData = (LPSTR)malloc(state->bufsize))) { ereturn(-1, "Out of memory for playback buffers."); } @@ -112,7 +127,7 @@ static int open_win32(out123_handle *ao) { /* Tell waveOutPrepareHeader the maximum value of dwBufferLength we will ever send */ - state->buffer_headers[i].dwBufferLength = BUFFER_SIZE; + state->buffer_headers[i].dwBufferLength = state->bufsize; state->buffer_headers[i].dwFlags = 0; res = waveOutPrepareHeader(state->waveout, &state->buffer_headers[i], sizeof(WAVEHDR)); if(res != MMSYSERR_NOERROR) ereturn(-1, "Can't write to audio output device (prepare)."); @@ -231,13 +246,13 @@ static int write_win32(out123_handle *ao, unsigned char *buf, int len) wait_for_buffer(hdr, state->play_done_event); /* Now see how much we want to stuff in and then stuff it in. */ - bufill = BUFFER_SIZE - hdr->dwBufferLength; + bufill = state->bufsize - hdr->dwBufferLength; if(len < bufill) bufill = len; rest_len = len - bufill; memcpy(hdr->lpData + hdr->dwBufferLength, buf, bufill); hdr->dwBufferLength += bufill; - if(hdr->dwBufferLength == BUFFER_SIZE) + if(hdr->dwBufferLength == state->bufsize) { /* Send the buffer out when it's full. */ hdr->dwFlags |= WHDR_PREPARED; diff --git a/src/libout123/out123_int.h b/src/libout123/out123_int.h index 3c395b2..33890ec 100644 --- a/src/libout123/out123_int.h +++ b/src/libout123/out123_int.h @@ -117,9 +117,5 @@ struct audio_format_name { char *sname; }; -int write_parameters(out123_handle *ao, int fd); -int read_parameters(out123_handle *ao -, int fd, byte *prebuf, int *preoff, int presize); - #endif diff --git a/src/local.c b/src/local.c index 9a1dc4e..10bb3e0 100644 --- a/src/local.c +++ b/src/local.c @@ -45,7 +45,7 @@ int utf8force = 0; // enforce UTF-8 workings int utf8env = 0; // produce UTF-8 text output int utf8loc = 0; // have actual UTF-8 locale (so that mbstowcs() works) -static int term_is_fun = -1; +//static int term_is_fun = -1; static const char joker_symbol = '?'; static const char *uni_repl = "\xef\xbf\xbd"; diff --git a/src/mpg123.c b/src/mpg123.c index c47f0f0..291b52a 100644 --- a/src/mpg123.c +++ b/src/mpg123.c @@ -103,6 +103,7 @@ struct parameter param = { ,1024 /* resync_limit */ ,0 /* smooth */ ,0.0 /* pitch */ + ,0.5 // pauseloop ,0 /* appflags */ ,NULL /* proxyurl */ ,0 /* keep_open */ @@ -483,7 +484,7 @@ static void set_appflag(char *arg, topt *opts) #if defined(NETWORK) || defined(NET123) static void set_httpauth(char *arg, topt *opts) { - param.httpauth = strdup(arg); + param.httpauth = compat_strdup(arg); // Do not advertise the password for all system users. memset(arg, 'x', strlen(arg)); } @@ -717,6 +718,7 @@ topt opts[] = { {'D', "delay", GLO_ARG | GLO_INT, 0, ¶m.delay, 0}, {0, "resync-limit", GLO_ARG | GLO_LONG, 0, ¶m.resync_limit, 0}, {0, "pitch", GLO_ARG|GLO_DOUBLE, 0, ¶m.pitch, 0}, + {0, "pauseloop", GLO_ARG|GLO_DOUBLE, 0, ¶m.pauseloop, 0}, #ifdef NETWORK {0, "ignore-mime", GLO_LONG, set_appflag, &appflag, MPG123APP_IGNORE_MIME }, #endif @@ -1093,6 +1095,10 @@ int main(int sys_argc, char ** sys_argv) print_outstr(stderr, prgName, 0, stderr_is_term); fprintf(stderr, ": Missing argument for option \"%s\".\n", loptarg); usage(1); + case GLO_BADARG: + print_outstr(stderr, prgName, 0, stderr_is_term); + fprintf(stderr, ": Bad option argument \"%s\".\n", loptarg); + usage(1); } /* Do this _after_ parameter parsing. */ utf8force = param.force_utf8; @@ -1298,9 +1304,16 @@ int main(int sys_argc, char ** sys_argv) ret = control_generic(mh); safe_exit(ret); } - if(param.term_ctrl == MAYBE) - param.term_ctrl = term_ctrl_default; - term_init(); + { + int term_forced = param.term_ctrl == TRUE; + if(param.term_ctrl == MAYBE) + param.term_ctrl = term_ctrl_default; + if(term_init() && term_forced) + { + error("Aborting since explicitly requested terminal control is not available."); + safe_exit(99); + } + } if(APPFLAG(MPG123APP_CONTINUE)) frames_left = param.frame_number; while ((fname = get_next_file())) @@ -1599,14 +1612,13 @@ static void long_usage(int err) fprintf(o," -y --no-resync DISABLES resync on error (--resync is deprecated)\n"); fprintf(o," -F --no-frankenstein disable support for Frankenstein streams\n"); #if defined(NETWORK) || defined(NET123) -#ifdef NETWORK - fprintf(o," -p --proxy set WWW proxy\n"); -#else + fprintf(o," -p --proxy override proxy environemnt variable for plain HTTP\n"); fprintf(o," --network select network backend, available: auto"); const char **nb = net123_backends; while(*nb){ fprintf(o, " %s", *nb++); } fprintf(o, "\n"); -#endif + fprintf(o," (auto meaning internal code for plain HTTP and the\n"); + fprintf(o," first external option for HTTPS)\n"); fprintf(o," -u --auth set auth values for HTTP access\n"); fprintf(o," --auth-file set auth values for HTTP access from given file\n"); fprintf(o," --ignore-mime ignore HTTP MIME types (content-type)\n"); @@ -1635,6 +1647,7 @@ static void long_usage(int err) fprintf(o," --list-devices list the available output devices for given output module\n"); fprintf(o," -a --audiodevice select audio device (depending on chosen module)\n"); fprintf(o," -s --stdout write raw audio to stdout (host native format)\n"); + fprintf(o," -O --outfile write raw audio to given file (- is stdout)\n"); fprintf(o," -w --wav write samples as WAV file in (- is stdout)\n"); fprintf(o," --au write samples as Sun AU file in (- is stdout)\n"); fprintf(o," --cdr write samples as raw CD audio file in (- is stdout)\n"); @@ -1703,6 +1716,7 @@ static void long_usage(int err) #ifndef GENERIC fprintf(o," --title set terminal title to filename\n"); #endif + fprintf(o," --pauseloop loop interval in (fractional) seconds\n"); fprintf(o," --name set instance name (used in various places)\n"); fprintf(o," --long-tag spacy id3 display with every item on a separate line\n"); fprintf(o," --lyrics show lyrics (from ID3v2 USLT frame)\n"); diff --git a/src/mpg123app.h b/src/mpg123app.h index 944ec4c..4d3be29 100644 --- a/src/mpg123app.h +++ b/src/mpg123app.h @@ -97,6 +97,7 @@ struct parameter long resync_limit; int smooth; double pitch; /* <0 or >0, 0.05 for 5% speedup. */ + double pauseloop; // terminal control 'pause' loop length unsigned long appflags; /* various switches for mpg123 application */ char *proxyurl; int keep_open; /* Whether to keep files open after end reached, for remote control mode, perhaps terminal control, too. */ diff --git a/src/net123.h b/src/net123.h index f6c725f..11f002e 100644 --- a/src/net123.h +++ b/src/net123.h @@ -39,12 +39,17 @@ #ifndef _MPG123_NET123_H_ #define _MPG123_NET123_H_ +#include "config.h" #include -// The network implementation defines the struct for private use. -// The purpose is just to keep enough context to be able to -// call net123_read() and net123_close() afterwards. -struct net123_handle_struct; +// stream handle for differing implementations, build-time plugins +struct net123_handle_struct +{ + void *parts; // custom internal data + // callbacks + size_t (*read)(struct net123_handle_struct *nh, void *buf, size_t bufsize); + void (*close)(struct net123_handle_struct *nh); +}; typedef struct net123_handle_struct net123_handle; extern const char *net123_backends[]; @@ -54,16 +59,16 @@ extern const char *net123_backends[]; // and then the raw data. // client_head contains header lines to send with the request, without // line ending -net123_handle *net123_open(const char *url, const char * const *client_head); -// Read data into buffer, return bytes read. -// This handles interrupts (EAGAIN, EINTR, ..) internally and only returns -// a short byte count on EOF or error. End of file or error is not distinguished: -// For the user, it only matters if there will be more bytes or not. -// Feel free to communicate errors via error() / merror() functions inside. -size_t net123_read(net123_handle *nh, void *buf, size_t bufsize); - -// Call that to free up resources, end processes. -void net123_close(net123_handle *nh); +// Variant for the external binding. +#ifdef NET123_EXEC +net123_handle *net123_open_exec(const char *url, const char * const *client_head); +#endif +#ifdef NET123_WININET +net123_handle *net123_open_wininet(const char *url, const char * const *client_head); +#endif +#ifdef NET123_WINHTTP +net123_handle *net123_open_winhttp(const char *url, const char * const *client_head); +#endif #endif diff --git a/src/net123_exec.c b/src/net123_exec.c index 0bb6403..93c4c37 100644 --- a/src/net123_exec.c +++ b/src/net123_exec.c @@ -8,6 +8,9 @@ specifically if param.network_backend is set accordingly. */ +// kill +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L #include "config.h" #include "net123.h" @@ -34,18 +37,11 @@ // wget --user=... --password=... // Alternatively: Have them in .netrc. -const char *net123_backends[] = -{ - "wget" -, "curl" -, NULL -}; - -struct net123_handle_struct +typedef struct { int fd; pid_t worker; -}; +} exec_handle; // Combine two given strings into one newly allocated one. // Use: (--parameter=, value) -> --parameter=value @@ -239,7 +235,36 @@ static char **curl_argv(const char *url, const char * const * client_head) return argv; } -net123_handle *net123_open(const char *url, const char * const * client_head) + +static size_t net123_read(net123_handle *nh, void *buf, size_t bufsize) +{ + if(!nh || (bufsize && !buf)) + return 0; + return unintr_read(((exec_handle*)nh->parts)->fd, buf, bufsize); +} + +static void net123_close(net123_handle *nh) +{ + if(!nh) + return; + exec_handle *eh = nh->parts; + if(eh->worker) + { + kill(eh->worker, SIGKILL); + errno = 0; + if(waitpid(eh->worker, NULL, 0) < 0) + merror("failed to wait for worker process: %s", strerror(errno)); + else if(param.verbose > 1) + fprintf(stderr, "Note: network helper %"PRIiMAX" finished\n", (intmax_t)eh->worker); + } + if(eh->fd > -1) + close(eh->fd); + free(nh->parts); + free(nh); +} + + +net123_handle *net123_open_exec(const char *url, const char * const * client_head) { int use_curl = 0; char * const curl_check_argv[] = { "curl", "--help", "all", NULL }; @@ -276,12 +301,21 @@ net123_handle *net123_open(const char *url, const char * const * client_head) } int fd[2]; - int hi = -1; // index of header value that might get a continuation line net123_handle *nh = malloc(sizeof(net123_handle)); - if(!nh) + exec_handle *eh = malloc(sizeof(exec_handle)); + if(!nh || !eh) + { + if(nh) + free(nh); + if(eh) + free(eh); return NULL; - nh->fd = -1; - nh->worker = 0; + } + nh->parts = eh; + nh->read = net123_read; + nh->close = net123_close; + eh->fd = -1; + eh->worker = 0; errno = 0; if(pipe(fd)) { @@ -293,15 +327,15 @@ net123_handle *net123_open(const char *url, const char * const * client_head) compat_binmode(fd[0], TRUE); compat_binmode(fd[1], TRUE); - nh->worker = fork(); - if(nh->worker == -1) + eh->worker = fork(); + if(eh->worker == -1) { merror("fork failed: %s", strerror(errno)); free(nh); return NULL; } - if(nh->worker == 0) + if(eh->worker == 0) { close(fd[0]); dup2(fd[1], STDOUT_FILENO); @@ -309,7 +343,6 @@ net123_handle *net123_open(const char *url, const char * const * client_head) dup2(infd, STDIN_FILENO); // child // Proxy environment variables can just be set in the user and inherited here, right? - int argc; char **argv = use_curl ? curl_argv(url, client_head) : wget_argv(url, client_head); if(!argv) @@ -338,35 +371,9 @@ net123_handle *net123_open(const char *url, const char * const * client_head) } // parent if(param.verbose > 1) - fprintf(stderr, "Note: started network helper with PID %"PRIiMAX"\n", (intmax_t)nh->worker); + fprintf(stderr, "Note: started network helper with PID %"PRIiMAX"\n", (intmax_t)eh->worker); errno = 0; close(fd[1]); - nh->fd = fd[0]; + eh->fd = fd[0]; return nh; } - -size_t net123_read(net123_handle *nh, void *buf, size_t bufsize) -{ - if(!nh || (bufsize && !buf)) - return 0; - return unintr_read(nh->fd, buf, bufsize); -} - -void net123_close(net123_handle *nh) -{ - if(!nh) - return; - if(nh->worker) - { - kill(nh->worker, SIGKILL); - errno = 0; - if(waitpid(nh->worker, NULL, 0) < 0) - merror("failed to wait for worker process: %s", strerror(errno)); - else if(param.verbose > 1) - fprintf(stderr, "Note: network helper %"PRIiMAX" finished\n", (intmax_t)nh->worker); - } - if(nh->fd > -1) - close(nh->fd); - free(nh); -} - diff --git a/src/net123_winhttp.c b/src/net123_winhttp.c index f02070f..4d1562b 100644 --- a/src/net123_winhttp.c +++ b/src/net123_winhttp.c @@ -5,13 +5,11 @@ #include #include -const char *net123_backends[] = { "(always winhttp)", NULL }; - // The network implementation defines the struct for private use. // The purpose is just to keep enough context to be able to // call net123_read() and net123_close() afterwards. #define URL_COMPONENTS_LENGTH 255 -struct net123_handle_struct { +typedef struct { HINTERNET session; HINTERNET connect; HINTERNET request; @@ -26,7 +24,7 @@ struct net123_handle_struct { size_t headers_pos, headers_len; DWORD internetStatus, internetStatusLength; LPVOID additionalInfo; -}; +} winhttp_handle; #define MPG123CONCAT_(x,y) x ## y #define MPG123CONCAT(x,y) MPG123CONCAT_(x,y) @@ -34,7 +32,7 @@ struct net123_handle_struct { #define MPG123STRINGIFY(x) MPG123STRINGIFY_(x) #define MPG123WSTR(x) MPG123CONCAT(L,MPG123STRINGIFY(x)) -static DWORD wrap_auth(net123_handle *nh){ +static DWORD wrap_auth(winhttp_handle *nh){ DWORD mode; DWORD ret; @@ -81,13 +79,16 @@ static void debug_crack(URL_COMPONENTS *comps){} static void WINAPI net123_ssl_errors(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength){ - net123_handle *nh = (net123_handle *)dwContext; + winhttp_handle *nh = (winhttp_handle *)dwContext; nh->internetStatus = dwInternetStatus; nh->additionalInfo = lpvStatusInformation; nh->internetStatusLength = dwStatusInformationLength; } -net123_handle *net123_open(const char *url, const char * const *client_head){ +static size_t net123_read(net123_handle *nh, void *buf, size_t bufsize); +static void net123_close(net123_handle *nh); + +net123_handle *net123_open_winhttp(const char *url, const char * const *client_head){ LPWSTR urlW = NULL, headers = NULL; size_t ii; WINBOOL res; @@ -101,8 +102,18 @@ net123_handle *net123_open(const char *url, const char * const *client_head){ win32_utf8_wide(url, &urlW, NULL); if(urlW == NULL) goto cleanup; - net123_handle *ret = calloc(1, sizeof(net123_handle)); - if (!ret) return ret; + winhttp_handle *ret = calloc(1, sizeof(winhttp_handle)); + if (!ret) goto cleanup; + + net123_handle *handle = calloc(1, sizeof(net123_handle)); + if (!handle) { + free(ret); + goto cleanup; + } + + handle->parts = ret; + handle->read = net123_read; + handle->close = net123_close; ret->comps.dwStructSize = sizeof(ret->comps); ret->comps.dwSchemeLength = 0; @@ -206,13 +217,13 @@ net123_handle *net123_open(const char *url, const char * const *client_head){ } debug("net123_open OK"); - return ret; + return handle; cleanup: debug("net123_open error"); if (urlW) free(urlW); - net123_close(ret); - ret = NULL; - return ret; + net123_close(handle); + handle = NULL; + return handle; } // Read data into buffer, return bytes read. @@ -221,20 +232,21 @@ cleanup: // For the user, it only matters if there will be more bytes or not. // Feel free to communicate errors via error() / merror() functions inside. size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){ + winhttp_handle *h = nh->parts; size_t ret; - size_t to_copy = nh->headers_len - nh->headers_pos; + size_t to_copy = h->headers_len - h->headers_pos; DWORD bytesread = 0; if(to_copy){ ret = to_copy <= bufsize ? to_copy : bufsize; - memcpy(buf, nh->headers + nh->headers_pos, ret); - nh->headers_pos += ret; + memcpy(buf, h->headers + h->headers_pos, ret); + h->headers_pos += ret; return ret; } /* is this needed? */ to_copy = bufsize > ULONG_MAX ? ULONG_MAX : bufsize; - if(!WinHttpReadData(nh->request, buf, to_copy, &bytesread)){ + if(!WinHttpReadData(h->request, buf, to_copy, &bytesread)){ return EOF; } return bytesread; @@ -242,21 +254,26 @@ size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){ // Call that to free up resources, end processes. void net123_close(net123_handle *nh){ - if(nh->headers) { - free(nh->headers); - nh->headers = NULL; - } - if(nh->request) { - WinHttpCloseHandle(nh->request); - nh->request = NULL; - } - if(nh->connect) { - WinHttpCloseHandle(nh->connect); - nh->connect = NULL; - } - if(nh->session) { - WinHttpCloseHandle(nh->session); - nh->session = NULL; + if (!nh) return; + winhttp_handle *h = nh->parts; + if(h) { + if(h->headers) { + free(h->headers); + h->headers = NULL; + } + if(h->request) { + WinHttpCloseHandle(h->request); + h->request = NULL; + } + if(h->connect) { + WinHttpCloseHandle(h->connect); + h->connect = NULL; + } + if(h->session) { + WinHttpCloseHandle(h->session); + h->session = NULL; + } + free(h); } free(nh); } diff --git a/src/net123_wininet.c b/src/net123_wininet.c index 49907e3..520c099 100644 --- a/src/net123_wininet.c +++ b/src/net123_wininet.c @@ -5,13 +5,11 @@ #include #include -const char *net123_backends[] = { "(always wininet)", NULL }; - // The network implementation defines the struct for private use. // The purpose is just to keep enough context to be able to // call net123_read() and net123_close() afterwards. #define URL_COMPONENTS_LENGTH 255 -struct net123_handle_struct { +typedef struct { HINTERNET session; HINTERNET connect; HINTERNET request; @@ -28,7 +26,7 @@ struct net123_handle_struct { DWORD HttpQueryInfoIndex; DWORD internetStatus, internetStatusLength; LPVOID additionalInfo; -}; +} wininet_handle; #define MPG123CONCAT_(x,y) x ## y #define MPG123CONCAT(x,y) MPG123CONCAT_(x,y) @@ -60,13 +58,17 @@ static void debug_crack(URL_COMPONENTSW *comps){} static void WINAPI net123_ssl_errors(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength){ - net123_handle *nh = (net123_handle *)dwContext; + debug("In net123_ssl_errors"); + wininet_handle *nh = (wininet_handle *)(dwContext); nh->internetStatus = dwInternetStatus; nh->additionalInfo = lpvStatusInformation; nh->internetStatusLength = dwStatusInformationLength; } -net123_handle *net123_open(const char *url, const char * const *client_head){ +static size_t net123_read(net123_handle *nh, void *buf, size_t bufsize); +static void net123_close(net123_handle *nh); + +net123_handle *net123_open_wininet(const char *url, const char * const *client_head){ LPWSTR urlW = NULL, headers = NULL; size_t ii; WINBOOL res; @@ -78,51 +80,63 @@ net123_handle *net123_open(const char *url, const char * const *client_head){ if(urlW == NULL) goto cleanup; net123_handle *ret = calloc(1, sizeof(net123_handle)); - if (!ret) return ret; + wininet_handle *wh = calloc(1, sizeof(wininet_handle)); + if(!ret || !wh) + { + if(ret) + free(ret); + if(wh) + free(wh); + return NULL; + } - ret->comps.dwStructSize = sizeof(ret->comps); - ret->comps.dwSchemeLength = URL_COMPONENTS_LENGTH - 1; - ret->comps.dwUserNameLength = URL_COMPONENTS_LENGTH - 1; - ret->comps.dwPasswordLength = URL_COMPONENTS_LENGTH - 1; - ret->comps.dwHostNameLength = URL_COMPONENTS_LENGTH - 1; - ret->comps.dwUrlPathLength = URL_COMPONENTS_LENGTH - 1; - ret->comps.dwExtraInfoLength = URL_COMPONENTS_LENGTH - 1; - ret->comps.lpszHostName = ret->lpszHostName; - ret->comps.lpszUserName = ret->lpszUserName; - ret->comps.lpszPassword = ret->lpszPassword; - ret->comps.lpszUrlPath = ret->lpszUrlPath; - ret->comps.lpszExtraInfo = ret->lpszExtraInfo; - ret->comps.lpszScheme = ret->lpszScheme; + ret->parts = wh; + ret->read = net123_read; + ret->close = net123_close; + + wh->comps.dwStructSize = sizeof(wh->comps); + wh->comps.dwSchemeLength = URL_COMPONENTS_LENGTH - 1; + wh->comps.dwUserNameLength = URL_COMPONENTS_LENGTH - 1; + wh->comps.dwPasswordLength = URL_COMPONENTS_LENGTH - 1; + wh->comps.dwHostNameLength = URL_COMPONENTS_LENGTH - 1; + wh->comps.dwUrlPathLength = URL_COMPONENTS_LENGTH - 1; + wh->comps.dwExtraInfoLength = URL_COMPONENTS_LENGTH - 1; + wh->comps.lpszHostName = wh->lpszHostName; + wh->comps.lpszUserName = wh->lpszUserName; + wh->comps.lpszPassword = wh->lpszPassword; + wh->comps.lpszUrlPath = wh->lpszUrlPath; + wh->comps.lpszExtraInfo = wh->lpszExtraInfo; + wh->comps.lpszScheme = wh->lpszScheme; debug1("net123_open start crack %S", urlW); - if(!(res = InternetCrackUrlW(urlW, 0, 0, &ret->comps))) { + if(!(res = InternetCrackUrlW(urlW, 0, 0, &wh->comps))) { debug1("net123_open crack fail %lu", GetLastError()); goto cleanup; } debug("net123_open crack OK"); - debug_crack(&ret->comps); + debug_crack(&wh->comps); - ret->session = InternetOpenW(useragent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + wh->session = InternetOpenW(useragent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); free(urlW); urlW = NULL; debug("net123_open InternetOpenW OK"); - if(!ret->session) goto cleanup; + if(!wh->session) goto cleanup; - debug2("net123_open InternetConnectW %S %u", ret->comps.lpszHostName, ret->comps.nPort); - ret->connect = InternetConnectW(ret->session, ret->comps.lpszHostName, ret->comps.nPort, - ret->comps.dwUserNameLength ? ret->comps.lpszUserName : NULL, ret->comps.dwPasswordLength ? ret->comps.lpszPassword : NULL, + debug2("net123_open InternetConnectW %S %u", wh->comps.lpszHostName, wh->comps.nPort); + wh->connect = InternetConnectW(wh->session, wh->comps.lpszHostName, wh->comps.nPort, + wh->comps.dwUserNameLength ? wh->comps.lpszUserName : NULL, wh->comps.dwPasswordLength ? wh->comps.lpszPassword : NULL, INTERNET_SERVICE_HTTP, 0, 0); - if(!ret->connect) goto cleanup; + if(!wh->connect) goto cleanup; debug("net123_open InternetConnectW OK"); - debug1("HttpOpenRequestW GET %S", ret->comps.lpszUrlPath); - ret->request = HttpOpenRequestW(ret->connect, L"GET", ret->comps.lpszUrlPath, NULL, NULL, NULL, ret->comps.nScheme == INTERNET_SCHEME_HTTPS ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)ret); - if(!ret->request) goto cleanup; + debug1("HttpOpenRequestW GET %S", wh->comps.lpszUrlPath); + wh->request = HttpOpenRequestW(wh->connect, L"GET", wh->comps.lpszUrlPath, NULL, NULL, NULL, wh->comps.nScheme == INTERNET_SCHEME_HTTPS ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)wh); + if(!wh->request) goto cleanup; debug("HttpOpenRequestW GET OK"); - cb = InternetSetStatusCallback(ret->request, (INTERNET_STATUS_CALLBACK)net123_ssl_errors); + cb = InternetSetStatusCallback(wh->request, (INTERNET_STATUS_CALLBACK)net123_ssl_errors); if(cb != NULL){ error1("InternetSetStatusCallback failed to install callback, errors might not be reported properly! (%lu)", GetLastError()); } @@ -132,7 +146,7 @@ net123_handle *net123_open(const char *url, const char * const *client_head){ if(!headers) goto cleanup; debug1("HttpAddRequestHeadersW add %S", headers); - res = HttpAddRequestHeadersW(ret->request, headers, (DWORD) -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + res = HttpAddRequestHeadersW(wh->request, headers, (DWORD) -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); debug2("HttpAddRequestHeadersW returns %u %lu", res, res ? 0 : GetLastError()); free(headers); headers = NULL; @@ -140,13 +154,14 @@ net123_handle *net123_open(const char *url, const char * const *client_head){ debug("net123_open ADD HEADERS OK"); - res = HttpSendRequestW(ret->request, NULL, 0, NULL, 0); + res = HttpSendRequestW(wh->request, NULL, 0, NULL, 0); if (!res) { res = GetLastError(); error1("HttpSendRequestW failed with %lu", res); goto cleanup; } + debug("HttpSendRequestW OK"); // dummy, cannot be null headers = calloc(1,1); @@ -155,18 +170,20 @@ net123_handle *net123_open(const char *url, const char * const *client_head){ error("Cannot allocate dummy buffer for HttpQueryInfoW"); goto cleanup; } - res = HttpQueryInfoW(ret->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &ret->HttpQueryInfoIndex); + debug("Try HttpQueryInfoW pass 1"); + res = HttpQueryInfoW(wh->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &wh->HttpQueryInfoIndex); free(headers); + debug("HttpQueryInfoW pass 1 OK"); if(!res && GetLastError() == ERROR_INSUFFICIENT_BUFFER && headerlen > 0) { /* buffer size is in bytes, not including terminator */ headers = calloc(1, headerlen + sizeof(*headers)); if (!headers) goto cleanup; - res = HttpQueryInfoW(ret->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &ret->HttpQueryInfoIndex); + res = HttpQueryInfoW(wh->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &wh->HttpQueryInfoIndex); debug3("HttpQueryInfoW returned %u, err %u : %S", res, GetLastError(), headers ? headers : L"null"); - win32_wide_utf7(headers, &ret->headers, &ret->headers_len); + win32_wide_utf7(headers, &wh->headers, &wh->headers_len); /* bytes written, skip the terminating null, we want to stop at the \r\n\r\n */ - ret->headers_len --; + wh->headers_len --; free(headers); headers = NULL; } else { @@ -184,21 +201,24 @@ cleanup: return ret; } -size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){ +static size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){ + if(!nh || !nh->parts) + return 0; + wininet_handle *wh = nh->parts; size_t ret; - size_t to_copy = nh->headers_len - nh->headers_pos; + size_t to_copy = wh->headers_len - wh->headers_pos; DWORD bytesread = 0; if(to_copy){ ret = to_copy <= bufsize ? to_copy : bufsize; - memcpy(buf, nh->headers + nh->headers_pos, ret); - nh->headers_pos += ret; + memcpy(buf, wh->headers + wh->headers_pos, ret); + wh->headers_pos += ret; return ret; } /* is this needed? */ to_copy = bufsize > ULONG_MAX ? ULONG_MAX : bufsize; - if(!InternetReadFile(nh->request, buf, to_copy, &bytesread)){ + if(!InternetReadFile(wh->request, buf, to_copy, &bytesread)){ error1("InternetReadFile exited with %d", GetLastError()); return EOF; } @@ -206,22 +226,28 @@ size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){ } // Call that to free up resources, end processes. -void net123_close(net123_handle *nh){ - if(nh->headers) { - free(nh->headers); - nh->headers = NULL; +static void net123_close(net123_handle *nh){ + if(!nh) + return; + wininet_handle *wh = nh->parts; + if(!wh) /*???*/ + return; + if(wh->headers) { + free(wh->headers); + wh->headers = NULL; } - if(nh->request) { - InternetCloseHandle(nh->request); - nh->request = NULL; + if(wh->request) { + InternetCloseHandle(wh->request); + wh->request = NULL; } - if(nh->connect) { - InternetCloseHandle(nh->connect); - nh->connect = NULL; + if(wh->connect) { + InternetCloseHandle(wh->connect); + wh->connect = NULL; } - if(nh->session) { - InternetCloseHandle(nh->session); - nh->session = NULL; + if(wh->session) { + InternetCloseHandle(wh->session); + wh->session = NULL; } free(nh); + free(wh); } diff --git a/src/out123.c b/src/out123.c index 3d4170b..cde049f 100644 --- a/src/out123.c +++ b/src/out123.c @@ -1516,6 +1516,9 @@ int main(int sys_argc, char ** sys_argv) case GLO_NOARG: fprintf (stderr, ME": missing argument for parameter: %s\n", loptarg); usage(1); + case GLO_BADARG: + fprintf(stderr, ME": bad option argument: %s\n", loptarg); + usage(1); } finish_endian(); mdebug("input byte flags: %ld, output byte flags: %ld", byte_in_flags, byte_out_flags); diff --git a/src/playlist.c b/src/playlist.c index fe48f54..c72e1c0 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -357,7 +357,8 @@ static int add_next_file (int argc, char *argv[], int args_utf8) } } pl.entry = 0; - if(pl.file && pl.file->network) +#ifdef NET123 + if(pl.file && pl.file->nh) { debug1("htd.content_type.p: %p", (void*) pl.file->htd.content_type.p); if(!APPFLAG(MPG123APP_IGNORE_MIME) && pl.file->htd.content_type.p != NULL) @@ -402,6 +403,7 @@ static int add_next_file (int argc, char *argv[], int args_utf8) } } } +#endif if(!pl.file) { param.listname = NULL; // why? diff --git a/src/streamdump.c b/src/streamdump.c index 92a7985..986b6a0 100644 --- a/src/streamdump.c +++ b/src/streamdump.c @@ -4,11 +4,15 @@ This evolved into the generic I/O interposer for direct file or http stream access, with explicit buffering for getline. - copyright 2010-2019 by the mpg123 project - free software under the terms of the LGPL 2.1 + copyright 2010-2022 by the mpg123 project - free software under the terms of the LGPL 2.1 see COPYING and AUTHORS files in distribution or http://mpg123.org initially written by Michael Hipp */ +// setenv +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L + #include "streamdump.h" #include #include @@ -18,6 +22,143 @@ #define O_BINARY 0 #endif +#ifndef HTTP_MAX_RELOCATIONS +#define HTTP_MAX_RELOCATIONS 20 +#endif + +#if defined(NETWORK) && !defined(NET123) +#error "NETWORK only with NET123 from now on!" +#endif +#if !defined(NETWORK) && defined(NET123) +#error "NET123 only with NETWORK from now on!" +#endif + + +#ifdef NETWORK + +const char *net123_backends[] = +{ + "internal" +#ifdef NET123_EXEC +, "wget" +, "curl" +#endif +#ifdef NET123_WINHTTP +, "winhttp" +#endif +#ifdef NET123_WININET +, "wininet" +#endif +, NULL +}; + +// Net123 variant for our internal code that has safer legacy support for HTTP shoutcast. + +static size_t net123_read_internal( struct net123_handle_struct *nh, +void *buf, size_t bufsize ) +{ + if(!nh) + return 0; + int *fdp = nh->parts; +#ifdef WANT_WIN32_SOCKETS + return win32_net_read(*fdp, buf, bufsize); +#else + return unintr_read(*fdp, buf, bufsize); +#endif + +} + +static void net123_close_internal(struct net123_handle_struct *nh) +{ + if(nh) + return; + int *fdp = nh->parts; +#ifdef WANT_WIN32_SOCKETS + if(*fdp != SOCKET_ERROR) + win32_net_close(*fdp); +#else + close(*fdp); +#endif + free(fdp); + free(nh); +} + +static net123_handle *net123_open_internal( const char *url +, const char * const *client_head, struct httpdata *hd ) +{ + net123_handle *nh = malloc(sizeof(net123_handle)); + if(!nh) + return NULL; + int *fdp = malloc(sizeof(int)); + if(!fdp) + { + free(nh); + return NULL; + } + nh->parts = fdp; + nh->read = net123_read_internal; + nh->close = net123_close_internal; + // Handles win32_net internally. + *fdp = http_open(url, hd, client_head); + if(*fdp >= 0) + return nh; + free(fdp); + free(nh); + return NULL; +} + +// Decide which backend to load. +static net123_handle *net123_open( const char *url +, const char * const *client_head, struct httpdata *hd ) +{ + int autochoose = !strcmp("auto", param.network_backend); + int https = !strncasecmp("https://", url, 8); + if(param.proxyurl) + { + if(strcmp(param.proxyurl, "none")) + { +#ifdef HAVE_SETENV + setenv("http_proxy", param.proxyurl, 1); + setenv("HTTP_PROXY", param.proxyurl, 1); + setenv("https_proxy", param.proxyurl, 1); + setenv("HTTPS_PROXY", param.proxyurl, 1); +#endif + } else + { +#ifdef HAVE_UNSETENV + unsetenv("http_proxy"); + unsetenv("HTTP_PROXY"); + unsetenv("https_proxy"); + unsetenv("HTTPS_PROXY"); +#endif + } + } + if( (autochoose && !https) + || !strcmp("internal", param.network_backend) ) + { + if(https && !param.quiet) + fprintf(stderr, "Note: HTTPS will fail with internal network code.\n"); + return net123_open_internal(url, client_head, hd); + } +#ifdef NET123_EXEC + if( autochoose + || !strcmp("wget", param.network_backend) + || !strcmp("curl", param.network_backend) ) + return net123_open_exec(url, client_head); +#endif +#ifdef NET123_WININET + if(autochoose || !strcmp("wininet", param.network_backend)) + return net123_open_wininet(url, client_head); +#endif +#ifdef NET123_WINHTTP + if(autochoose || !strcmp("winhttp", param.network_backend)) + return net123_open_winhttp(url, client_head); +#endif + merror("no network backend for %s", https ? "HTTPS" : "HTTP"); + return NULL; +} +#endif + /* Stream dump descriptor. */ static int dump_fd = -1; @@ -27,13 +168,9 @@ static int dump_fd = -1; static ssize_t stream_read_raw(struct stream *sd, void *buf, size_t count) { ssize_t ret = -1; -#ifdef NET123 +#ifdef NETWORK if(sd->nh) - ret = net123_read(sd->nh, buf, count); -#endif -#ifdef WANT_WIN32_SOCKETS - if(sd->fd >= 0 && sd->network) - ret = win32_net_read(sd->fd, buf, count); + ret = (ssize_t) sd->nh->read(sd->nh, buf, count); #endif if(sd->fd >= 0) // plain file or network socket ret = (ssize_t) unintr_read(sd->fd, buf, count); @@ -75,8 +212,12 @@ static ssize_t stream_read(struct stream *sd, void *buf, size_t count) static off_t stream_seek(struct stream *sd, off_t pos, int whence) { - if(!sd || sd->network) + if(!sd) return -1; +#ifdef NET123 + if(sd->nh) + return -1; +#endif return lseek(sd->fd, pos, whence); } @@ -147,15 +288,22 @@ ssize_t stream_getline(struct stream *sd, mpg123_string *line) } } -int stream_parse_headers(struct stream *sd) +#ifdef NETWORK +// Return 0 on success, non-zero when there is an error or more work to do. +// -1: error, 1: redirection to given location +static int stream_parse_headers(struct stream *sd, mpg123_string *location) { int ret = 0; mpg123_string line; mpg123_init_string(&line); mpg123_string icyint; mpg123_init_string(&icyint); - const char *head[] = { "content-type", "icy-name", "icy-url", "icy-metaint" }; - mpg123_string *val[] = { &sd->htd.content_type, &sd->htd.icy_name, &sd->htd.icy_url, &icyint }; + int redirect = 0; + location->fill = 0; + const char *head[] = { "content-type", "icy-name" + , "icy-url", "icy-metaint", "location" }; + mpg123_string *val[] = { &sd->htd.content_type, &sd->htd.icy_name + , &sd->htd.icy_url, &icyint, location }; int hn = sizeof(head)/sizeof(char*); int hi = -1; int got_ok = 0; @@ -171,6 +319,8 @@ int stream_parse_headers(struct stream *sd) } // React to HTTP error codes, but do not enforce an OK being sent as Shoutcast // only produces very minimal headers, not even a HTTP response code. + // Well, ICY 200 OK could be there, but then we got other headers to know + // things are fine. if(!strncasecmp("http/", line.p, 5)) { // HTTP/1.1 200 OK @@ -181,9 +331,17 @@ int stream_parse_headers(struct stream *sd) ++tok; if(tok && *tok != '2') { - merror("HTTP error response: %s", line.p); - ret = -1; - break; + if(*tok == '3') + { + redirect = ret = 1; + if(param.verbose > 2) + fprintf(stderr, "Note: HTTP redirect\n"); + } else + { + merror("HTTP error response: %s", line.p); + ret = -1; + break; + } } else if(tok && *tok == '2') { if(param.verbose > 2) @@ -235,7 +393,7 @@ int stream_parse_headers(struct stream *sd) continue; } } - if(icyint.fill) + if(!redirect && icyint.fill) { sd->htd.icy_interval = atol(icyint.p); if(param.verbose > 1) @@ -245,6 +403,9 @@ int stream_parse_headers(struct stream *sd) { error("no data at all from network resource"); ret = -1; + } else if(redirect && !location->fill) + { + error("redirect but no location given"); } else if(!got_ok) { error("missing positive server response"); @@ -255,11 +416,84 @@ int stream_parse_headers(struct stream *sd) return ret; } +// resolve relative locations given the initial full URL +// full URL ensured to either start with http:// or https:// +// (case-insensitive), location non-empty +static void relocate_url(mpg123_string *location, const char *url) +{ + if(!strncasecmp(location->p, "http://", 7) || !strncasecmp(location->p, "https://", 8)) + return; + if(!url || (strncasecmp(url, "http://", 7) && strncasecmp(url, "https://", 8))) + { + mpg123_resize_string(location, 0); + return; + } + + if(!param.quiet) + fprintf(stderr, "NOTE: no complete URL in redirect, constructing one\n"); + + mpg123_string purl; + mpg123_string workbuf; + mpg123_init_string(&purl); + mpg123_init_string(&workbuf); + + if(mpg123_set_string(&purl, url) && mpg123_move_string(location, &workbuf)) + { + debug1("relocate request_url: %s", purl.p); + // location somewhat relative, either /some/path or even just some/path + char* ptmp = NULL; + // Though it's not RFC (?), accept relative URIs as wget does. + if(workbuf.p[0] == '/') + { + // server-absolute only prepend http://server/ + // I null the first / after http:// or https:// + size_t off = (purl.p[4] == 's') ? 8 : 7; + ptmp = strchr(purl.p+off,'/'); + if(ptmp != NULL) + { + purl.fill = ptmp-purl.p+1; + purl.p[purl.fill-1] = 0; + } + } + else + { + // relative to current directory + // prepend http://server/path/ + // first cutting off parameter stuff from URL + for(size_t i=0; ibufp = sd->buf; sd->fill = 0; - sd->network = 0; sd->fd = -1; #ifdef NET123 sd->nh = NULL; @@ -267,6 +501,24 @@ static void stream_init(struct stream *sd) httpdata_init(&sd->htd); } +// Clean up things for another connection. +// Does not reset the network flag. +static void stream_reset(struct stream *sd) +{ +#ifdef NET123 + if(sd->nh) + sd->nh->close(sd->nh); + sd->nh = NULL; +#endif + if(sd->fd >= 0) // plain file or network socket + close(sd->fd); + sd->fd = -1; + httpdata_free(&sd->htd); + httpdata_init(&sd->htd); + sd->bufp = sd->buf; + sd->fill = 0; +} + struct stream *stream_open(const char *url) { struct stream *sd = malloc(sizeof(struct stream)); @@ -279,10 +531,9 @@ struct stream *stream_open(const char *url) sd->fd = STDIN_FILENO; compat_binmode(STDIN_FILENO, TRUE); } -#ifdef NET123 +#ifdef NETWORK else if(!strncasecmp("http://", url, 7) || !strncasecmp("https://", url, 8)) { - sd->network = 1; // Network stream with header parsing. const char *client_head[] = { NULL, NULL, NULL }; client_head[0] = param.talk_icy ? icy_yes : icy_no; @@ -290,26 +541,51 @@ struct stream *stream_open(const char *url) mpg123_init_string(&accept); append_accept(&accept); client_head[1] = accept.p; - sd->nh = net123_open(url, client_head); - if(!sd->nh || stream_parse_headers(sd)) + mpg123_string location; + mpg123_string urlcopy; + mpg123_init_string(&location); + mpg123_init_string(&urlcopy); + int numrelocs = 0; + while(sd) { - stream_close(sd); - return NULL; - } - } -#elif defined(NETWORK) - else if(!strncasecmp("http://", url, 7)) - { -#ifdef WANT_WIN32_SOCKETS - sd->fd = win32_net_http_open(url, &sd->htd); -#else - sd->fd = http_open(url, &sd->htd); -#endif - if(sd->fd < 0) - { - stream_close(sd); - return NULL; + sd->nh = net123_open(url, client_head, &sd->htd); + if(!sd->nh) + { + stream_close(sd); + sd = NULL; + break; + } + location.fill = 0; + if(stream_parse_headers(sd, &location)) + { + stream_reset(sd); + if(location.fill) + { + if(++numrelocs > HTTP_MAX_RELOCATIONS) + { + merror("too many HTTP redirections: %i", numrelocs); + url = NULL; + } else + { + relocate_url(&location, url); // resolve relative locations + mpg123_copy_string(&location, &urlcopy); + url = urlcopy.p; + } + } else + { + url = NULL; + } + if(!url) + { + stream_close(sd); + sd = NULL; + } + } else break; // Successful end. } + mpg123_free_string(&urlcopy); + mpg123_free_string(&location); + mpg123_free_string(&accept); + // Either sd is NULL or we got a stream ready. } #endif else @@ -333,20 +609,7 @@ void stream_close(struct stream *sd) { if(!sd) return; -#ifdef NET123 - if(sd->nh) - net123_close(sd->nh); -#endif -#ifdef WANT_WIN32_SOCKETS - if(sd->fd >= 0 && sd->network) - { - if(sd->fd != SOCKET_ERROR) - win32_net_close(sd->fd); - } -#endif - if(sd->fd >= 0) // plain file or network socket - close(sd->fd); - httpdata_free(&sd->htd); + stream_reset(sd); free(sd); } @@ -419,12 +682,7 @@ int dump_setup(struct stream *sd, mpg123_handle *mh) ret = mpg123_open_handle(mh, sd); } else { -#ifdef WANT_WIN32_SOCKETS - if(sd->network) - win32_net_replace(mh); - else // ensure libmpg123 is using its own reader otherwise -#endif - mpg123_replace_reader(mh, NULL, NULL); + mpg123_replace_reader(mh, NULL, NULL); ret = mpg123_open_fd(mh, sd->fd); } if(ret != MPG123_OK) diff --git a/src/streamdump.h b/src/streamdump.h index c220b62..5bb93a0 100644 --- a/src/streamdump.h +++ b/src/streamdump.h @@ -18,6 +18,9 @@ #ifdef NET123 #include "net123.h" #endif +#ifdef NETWORK +#include "httpget.h" +#endif // The stream is either addressed via file descriptor or net123 handle. struct stream @@ -25,7 +28,6 @@ struct stream char buf[256]; // buffer for getline char *bufp; // read pointer in buffer int fill; // bytes in buffer - int network; // flag to mark network streams (with httpdata) int fd; // if > 0: plain file descriptor or win32 net socket struct httpdata htd; #ifdef NET123 diff --git a/src/term.c b/src/term.c index 2e9594a..1dd86e9 100644 --- a/src/term.c +++ b/src/term.c @@ -17,22 +17,26 @@ #include "debug.h" static int term_enable = 0; +static const char *extrabreak = ""; int seeking = FALSE; extern out123_handle *ao; +static const int helplen = 18; +#define HELPFMT "%-18s" + /* Hm, next step would be some system in this, plus configurability... Two keys for everything? It's just stop/pause for now... */ struct keydef { const char key; const char key2; const char* desc; }; struct keydef term_help[] = { - { MPG123_STOP_KEY, ' ', "interrupt/restart playback (i.e. '(un)pause')" } + { MPG123_STOP_KEY, ' ', "(un)pause playback" } ,{ MPG123_NEXT_KEY, 0, "next track" } ,{ MPG123_PREV_KEY, 0, "previous track" } - ,{ MPG123_NEXT_DIR_KEY, 0, "next directory (next track until directory part changes)" } - ,{ MPG123_PREV_DIR_KEY, 0, "previous directory (previous track until directory part changes)" } - ,{ MPG123_BACK_KEY, 0, "back to beginning of track" } - ,{ MPG123_PAUSE_KEY, 0, "loop around current position (don't combine with output buffer)" } + ,{ MPG123_NEXT_DIR_KEY, 0, "next directory" } + ,{ MPG123_PREV_DIR_KEY, 0, "previous directory" } + ,{ MPG123_BACK_KEY, 0, "back to beginning" } + ,{ MPG123_PAUSE_KEY, 0, "loop (--pauseloop)" } ,{ MPG123_FORWARD_KEY, 0, "forward" } ,{ MPG123_REWIND_KEY, 0, "rewind" } ,{ MPG123_FAST_FORWARD_KEY, 0, "fast forward" } @@ -42,19 +46,19 @@ struct keydef term_help[] = ,{ MPG123_VOL_UP_KEY, 0, "volume up" } ,{ MPG123_VOL_DOWN_KEY, 0, "volume down" } ,{ MPG123_VOL_MUTE_KEY, 0, "(un)mute volume" } - ,{ MPG123_RVA_KEY, 0, "RVA switch" } - ,{ MPG123_VERBOSE_KEY, 0, "verbose switch" } - ,{ MPG123_PLAYLIST_KEY, 0, "list current playlist, indicating current track there" } - ,{ MPG123_TAG_KEY, 0, "display tag info (again)" } - ,{ MPG123_MPEG_KEY, 0, "print MPEG header info (again)" } - ,{ MPG123_PITCH_UP_KEY, MPG123_PITCH_BUP_KEY, "pitch up (small step, big step)" } - ,{ MPG123_PITCH_DOWN_KEY, MPG123_PITCH_BDOWN_KEY, "pitch down (small step, big step)" } - ,{ MPG123_PITCH_ZERO_KEY, 0, "reset pitch to zero" } - ,{ MPG123_BOOKMARK_KEY, 0, "print out current position in playlist and track, for the benefit of some external tool to store bookmarks" } + ,{ MPG123_RVA_KEY, 0, "cycle RVA modes" } + ,{ MPG123_VERBOSE_KEY, 0, "cycle verbosity" } + ,{ MPG123_PLAYLIST_KEY, 0, "show playlist" } + ,{ MPG123_TAG_KEY, 0, "tag info" } + ,{ MPG123_MPEG_KEY, 0, "MPEG header info" } + ,{ MPG123_PITCH_UP_KEY, MPG123_PITCH_BUP_KEY, "pitch up + ++" } + ,{ MPG123_PITCH_DOWN_KEY, MPG123_PITCH_BDOWN_KEY, "pitch down - --" } + ,{ MPG123_PITCH_ZERO_KEY, 0, "zero pitch" } + ,{ MPG123_BOOKMARK_KEY, 0, "print bookmark" } ,{ MPG123_HELP_KEY, 0, "this help" } ,{ MPG123_QUIT_KEY, 0, "quit" } - ,{ MPG123_EQ_RESET_KEY, 0, "reset to a flat equalizer" } - ,{ MPG123_EQ_SHOW_KEY, 0, "show our current rough equalizer settings" } + ,{ MPG123_EQ_RESET_KEY, 0, "flat equalizer" } + ,{ MPG123_EQ_SHOW_KEY, 0, "show equalizer" } ,{ MPG123_BASS_UP_KEY, 0, "more bass" } ,{ MPG123_BASS_DOWN_KEY, 0, "less bass" } ,{ MPG123_MID_UP_KEY, 0, "more mids" } @@ -64,7 +68,7 @@ struct keydef term_help[] = }; /* initialze terminal */ -void term_init(void) +int term_init(void) { const char hide_cursor[] = "\x1b[?25l"; debug("term_init"); @@ -72,9 +76,11 @@ void term_init(void) if(term_have_fun(STDERR_FILENO, param.term_visual)) fprintf(stderr, "%s", hide_cursor); + if(param.verbose) + extrabreak = "\n"; debug1("param.term_ctrl: %i", param.term_ctrl); if(!param.term_ctrl) - return; + return 0; term_enable = 0; errno = 0; @@ -84,9 +90,10 @@ void term_init(void) merror("failed to set up terminal: %s", strerror(errno)); else error("failed to set up terminal"); - return; + return -1; } term_enable = 1; + return 0; } void term_hint(void) @@ -127,7 +134,7 @@ void pause_recycle(mpg123_handle *fr) { /* Take care not to go backwards in time in steps of 1 frame That is what the +1 is for. */ - pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr)); + pause_cycle=(int)(param.pauseloop/mpg123_tpf(fr)); offset-=pause_cycle; } @@ -153,7 +160,7 @@ off_t term_control(mpg123_handle *fr, out123_handle *ao) do { off_t old_offset = offset; - term_handle_input(fr, ao, stopped|seeking); + term_handle_input(fr, ao, seeking); if((offset < 0) && (-offset > framenum)) offset = - framenum; if(param.verbose && offset != old_offset) print_stat(fr,offset,ao,1,¶m); @@ -204,6 +211,20 @@ static void seekmode(mpg123_handle *mh, out123_handle *ao) } } +static void print_term_help(struct keydef *def) +{ + if(def->key2) + { + if(isspace(def->key2)) + fprintf(stderr, "%c '%c'", def->key, def->key2); + else + fprintf(stderr, "%c %c ", def->key, def->key2); + } + else fprintf(stderr, "%c ", def->key); + + fprintf(stderr, " " HELPFMT, def->desc); +} + static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) { debug1("term_handle_key: %c", val); @@ -212,7 +233,7 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) case MPG123_BACK_KEY: out123_pause(ao); out123_drop(ao); - if(paused) pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr)); + if(paused) pause_cycle=(int)(param.pauseloop/mpg123_tpf(fr)); if(mpg123_seek_frame(fr, 0, SEEK_SET) < 0) error1("Seek to begin failed: %s", mpg123_strerror(fr)); @@ -232,8 +253,9 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) case MPG123_QUIT_KEY: debug("QUIT"); if(stopped) - { if(param.verbose) - print_stat(fr,0,ao,0,¶m); + { + if(param.verbose) + print_stat(fr,0,ao,0,¶m); stopped = 0; out123_pause(ao); /* no chance for annoying underrun warnings */ @@ -244,13 +266,23 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) break; case MPG123_PAUSE_KEY: paused=1-paused; + size_t buffered = out123_buffered(ao); out123_pause(ao); /* underrun awareness */ out123_drop(ao); if(paused) { - /* Not really sure if that is what is wanted - This jumps in audio output, but has direct reaction to pausing loop. */ + // Make output buffer react immediately, dropping decoded audio + // and (at least trying to) seeking back in input. out123_param_float(ao, OUT123_PRELOAD, 0.); + if(buffered) + { + int framesize = 1; + if(!out123_getformat(ao, NULL, NULL, NULL, &framesize)) + { + buffered /= framesize; + mpg123_seek(fr, -buffered, SEEK_CUR); + } + } pause_recycle(fr); } else @@ -326,7 +358,8 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) print_stat(fr,0,ao,0,¶m); // Assuming only changes happen via terminal control, these 3 values // are what counts. - fprintf( stderr, "\n\nbass: %.3f\nmid: %.3f\ntreble: %.3f\n\n" + fprintf( stderr, "%s\nbass: %.3f\nmid: %.3f\ntreble: %.3f\n\n" + , extrabreak , mpg123_geteq(fr, MPG123_LEFT, 0) , mpg123_geteq(fr, MPG123_LEFT, 1) , mpg123_geteq(fr, MPG123_LEFT, 2) @@ -381,7 +414,9 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) { param.verbose = 0; clear_stat(); - } + extrabreak = ""; + } else + extrabreak = "\n"; mpg123_param(fr, MPG123_VERBOSE, param.verbose, 0); break; case MPG123_RVA_KEY: @@ -412,34 +447,38 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) case MPG123_TAG_KEY: if(param.verbose) print_stat(fr,0,ao,0,¶m); - fprintf(stderr, "%s\n", param.verbose ? "\n" : ""); + fprintf(stderr, "%s", extrabreak); print_id3_tag(fr, param.long_id3, stderr, term_width(STDERR_FILENO)); break; case MPG123_MPEG_KEY: if(param.verbose) print_stat(fr,0,ao,0,¶m); - fprintf(stderr, "\n"); + fprintf(stderr, "%s", extrabreak); if(param.verbose > 1) print_header(fr); else print_header_compact(fr); - fprintf(stderr, "\n"); break; case MPG123_HELP_KEY: { /* This is more than the one-liner before, but it's less spaghetti. */ int i; if(param.verbose) print_stat(fr,0,ao,0,¶m); - fprintf(stderr,"\n\n -= terminal control keys =-\n"); + fprintf(stderr,"%s\n -= terminal control keys =-\n\n", extrabreak); + int linelen = term_width(STDERR_FILENO); + int colwidth = helplen+6; + int columns = linelen > colwidth ? ((linelen+2)/(colwidth+2)) : 1; + int j = 0; for(i=0; i<(sizeof(term_help)/sizeof(struct keydef)); ++i) { - if(term_help[i].key2) fprintf(stderr, "[%c] or [%c]", term_help[i].key, term_help[i].key2); - else fprintf(stderr, "[%c]", term_help[i].key); - - fprintf(stderr, "\t%s\n", term_help[i].desc); + if(j) + fprintf(stderr, " "); + print_term_help(term_help+i); + j = (j+1)%columns; + if(!j) + fprintf(stderr, "\n"); } - fprintf(stderr, "\nAlso, the number row (starting at 1, ending at 0) gives you jump points into the current track at 10%% intervals.\n"); - fprintf(stderr, "\n"); + fprintf(stderr, "\n\nNumber row jumps in 10%% steps.\n\n"); } break; case MPG123_FRAME_INDEX_KEY: @@ -508,7 +547,7 @@ static void term_handle_input(mpg123_handle *fr, out123_handle *ao, int do_delay { char val; /* Do we really want that while loop? This means possibly handling multiple inputs that come very rapidly in one go. */ - while(term_get_key(do_delay, &val)) + while(term_get_key(stopped, do_delay, &val)) { term_handle_key(fr, ao, val); } diff --git a/src/term.h b/src/term.h index fc32b91..fa00f0b 100644 --- a/src/term.h +++ b/src/term.h @@ -12,8 +12,6 @@ #include "mpg123app.h" #include "audio.h" -#define LOOP_CYCLES 0.500000 /* Loop time in sec */ - /* * Defines the keybindings in term.c - change to your * own preferences. @@ -87,7 +85,7 @@ #define MPG123_TERM_USR2 "f" -void term_init(void); +int term_init(void); // -1 on error, 0 success or no terminal desired void term_exit(void); off_t term_control(mpg123_handle *mh, out123_handle *ao); void term_hint(void); /* Print a message hinting at terminal usage. */ diff --git a/src/term_none.c b/src/term_none.c index ec24e08..0875b79 100644 --- a/src/term_none.c +++ b/src/term_none.c @@ -25,7 +25,7 @@ void term_restore(void) { } -int term_get_key(int do_delay, char *val) +int term_get_key(int stopped, int do_delay, char *val) { return 0; } diff --git a/src/term_posix.c b/src/term_posix.c index ba1d161..278ce7d 100644 --- a/src/term_posix.c +++ b/src/term_posix.c @@ -8,6 +8,10 @@ initially written by Thomas Orgis */ +// ctermid +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L + #include "config.h" #ifdef __OS2__ @@ -176,7 +180,7 @@ int term_setup(void) /* Get the next pressed key, if any. Returns 1 when there is a key, 0 if not. */ -int term_get_key(int do_delay, char *val) +int term_get_key(int stopped, int do_delay, char *val) { #ifdef __OS2__ KBDKEYINFO key; @@ -184,7 +188,7 @@ int term_get_key(int do_delay, char *val) key.chScan = 0; if(do_delay) DosSleep(10); - if(!KbdCharIn(&key,IO_NOWAIT,0) && key.chChar) + if(!KbdCharIn(&key,(stopped) ? IO_WAIT : IO_NOWAIT,0) && key.chChar) { *val = key.chChar; return 1; @@ -207,7 +211,8 @@ int term_get_key(int do_delay, char *val) FD_ZERO(&r); FD_SET(term_fd,&r); - if(select(term_fd+1,&r,NULL,NULL,&t) > 0 && FD_ISSET(term_fd,&r)) + /* No timeout if stopped */ + if(select(term_fd+1,&r,NULL,NULL,(stopped) ? NULL : &t) > 0 && FD_ISSET(term_fd,&r)) { if(read(term_fd,val,1) <= 0) return 0; /* Well, we couldn't read the key, so there is none. */ diff --git a/src/term_win32.c b/src/term_win32.c index cf8e221..aad82d6 100644 --- a/src/term_win32.c +++ b/src/term_win32.c @@ -90,7 +90,7 @@ int term_present(void){ /* Get the next pressed key, if any. Returns 1 when there is a key, 0 if not. */ -int term_get_key(int do_delay, char *val){ +int term_get_key(int stopped, int do_delay, char *val){ INPUT_RECORD record; HANDLE input; DWORD res; @@ -99,7 +99,7 @@ int term_get_key(int do_delay, char *val){ if(input == NULL || input == INVALID_HANDLE_VALUE) return 0; - while(WaitForSingleObject(input, do_delay ? 10 : 0) == WAIT_OBJECT_0){ + while(WaitForSingleObject(input, stopped ? INFINITE : (do_delay ? 10 : 0)) == WAIT_OBJECT_0){ do_delay = 0; if(!ReadConsoleInput(input, &record, 1, &res)) return 0; diff --git a/src/terms.h b/src/terms.h index 1952587..328786b 100644 --- a/src/terms.h +++ b/src/terms.h @@ -47,6 +47,6 @@ void term_restore(void); * \param val address to store character to * \return 1 if there is a key, 0 if not */ -int term_get_key(int do_delay, char *val); +int term_get_key(int stopped, int do_delay, char *val); #endif diff --git a/src/tests/seek_accuracy.c b/src/tests/seek_accuracy.c index a660577..b7901ff 100644 --- a/src/tests/seek_accuracy.c +++ b/src/tests/seek_accuracy.c @@ -86,7 +86,7 @@ int main(int argc, char **argv) fprintf(stderr,"1to1 non-indexed seek errors: %"SIZE_P" / %"SIZE_P"\n", (size_p)errs[1],(size_p)samples); fprintf(stderr,"NtoM indexed seek errors: %"SIZE_P" / %"SIZE_P"\n", (size_p)errs_ntom[0],(size_p)samples); fprintf(stderr,"NtoM non-indexed seek errors: %"SIZE_P" / %"SIZE_P"\n", (size_p)errs_ntom[1],(size_p)samples); - fprintf(stderr,"Errors in getting first sample again: %"SIZE_P"\n", first_sample_errs); + fprintf(stderr,"Errors in getting first sample again: %"SIZE_P"\n", (size_p)first_sample_errs); fprintf(stderr,"\n"); if(ret == 0) diff --git a/src/win32_net.c b/src/win32_net.c index 11a5a42..e43ddd4 100755 --- a/src/win32_net.c +++ b/src/win32_net.c @@ -1,14 +1,7 @@ -#include "config.h" -#include "mpg123.h" +#include "win32_support.h" #include "mpg123app.h" -#include "httpget.h" -#include "resolver.h" -#include "compat.h" -#include - #include "debug.h" -#if defined (WANT_WIN32_SOCKETS) #ifdef DEBUG #define msgme(x) win32_net_msg(x,__FILE__,__LINE__) #define msgme1 win32_net_msg(1,__FILE__,__LINE__) @@ -115,28 +108,6 @@ static int get_sock_ch (int sock) return (((int) c)&0xff); return -1; } -/* Addapted from from newlib*/ -char *win32_net_fgets(char *s, int n, int stream) -{ - char c = 0; - char *buf; - buf = s; - debug1("Pseudo net fgets attempts to read %d bytes from network.", n - 1); - while (--n > 0 && (c = get_sock_ch (stream)) != -1) - { - *s++ = c; - if (c == '\n' || c == '\r') - break; - } - debug1("Pseudo net fgets got %"SIZE_P" bytes.", (size_p)(s - buf)); - if (c == -1 && s == buf) - { - debug("Pseudo net fgets met a premature end."); - return NULL; - } - *s = 0; - return buf; -} ssize_t win32_net_write (int fildes, const void *buf, size_t nbyte) { @@ -148,18 +119,6 @@ ssize_t win32_net_write (int fildes, const void *buf, size_t nbyte) return ret; } -off_t win32_net_lseek (int a, off_t b, int c) -{ - debug("lseek on a socket called!"); - return -1; -} - -void win32_net_replace (mpg123_handle *fr) -{ - debug("win32_net_replace ran"); - mpg123_replace_reader(fr, win32_net_read, win32_net_lseek); -} - static int win32_net_timeout_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) { debug("win32_net_timeout_connect ran"); @@ -239,7 +198,7 @@ static int win32_net_timeout_connect(int sockfd, const struct sockaddr *serv_add } } -static int win32_net_open_connection(mpg123_string *host, mpg123_string *port) +int win32_net_open_connection(mpg123_string *host, mpg123_string *port) { struct addrinfo hints; struct addrinfo *addr, *addrlist; @@ -286,52 +245,10 @@ static int win32_net_open_connection(mpg123_string *host, mpg123_string *port) } freeaddrinfo(addrlist); - return 1; + return ws.local_socket == SOCKET_ERROR ? -1 : 1; } -static size_t win32_net_readstring (mpg123_string *string, size_t maxlen, int fd) -{ - debug2("Attempting readstring on %d for %"SIZE_P" bytes", fd, (size_p)maxlen); - int err; - string->fill = 0; - while(maxlen == 0 || string->fill < maxlen) - { - if(string->size-string->fill < 1) - if(!mpg123_grow_string(string, string->fill+4096)) - { - error("Cannot allocate memory for reading."); - string->fill = 0; - return 0; - } - err = win32_net_read(0,string->p+string->fill,1); /*fd is ignored */ - /* Whoa... reading one byte at a time... one could ensure the line break in another way, but more work. */ - if( err == 1) - { - string->fill++; - if(string->p[string->fill-1] == '\n') break; - } - else if(errno != EINTR) - { - error("Error reading from socket or unexpected EOF."); - string->fill = 0; - /* bail out to prevent endless loop */ - return 0; - } - } - - if(!mpg123_grow_string(string, string->fill+1)) - { - string->fill=0; - } - else - { - string->p[string->fill] = 0; - string->fill++; - } - return string->fill; -} - -static int win32_net_writestring (int fd, mpg123_string *string) +int win32_net_writestring (int fd, mpg123_string *string) { size_t result, bytes; char *ptr = string->p; @@ -355,253 +272,3 @@ static int win32_net_writestring (int fd, mpg123_string *string) } return TRUE; } - -static int win32_net_resolve_redirect(mpg123_string *response, mpg123_string *request_url, mpg123_string *purl) -{ - debug1("request_url:%s", request_url->p); - /* initialized with full old url */ - if(!mpg123_copy_string(request_url, purl)) return FALSE; - - /* We may strip it down to a prefix ot totally. */ - if(strncasecmp(response->p, "Location: http://", 17)) - { /* OK, only partial strip, need prefix for relative path. */ - char* ptmp = NULL; - /* though it's not RFC (?), accept relative URIs as wget does */ - fprintf(stderr, "NOTE: no complete URL in redirect, constructing one\n"); - /* not absolute uri, could still be server-absolute */ - /* I prepend a part of the request... out of the request */ - if(response->p[10] == '/') - { - /* only prepend http://server/ */ - /* I null the first / after http:// */ - ptmp = strchr(purl->p+7,'/'); - if(ptmp != NULL){ purl->fill = ptmp-purl->p+1; purl->p[purl->fill-1] = 0; } - } - else - { - /* prepend http://server/path/ */ - /* now we want the last / */ - ptmp = strrchr(purl->p+7, '/'); - if(ptmp != NULL){ purl->fill = ptmp-purl->p+2; purl->p[purl->fill-1] = 0; } - } - } - else purl->fill = 0; - - debug1("prefix=%s", purl->fill ? purl->p : ""); - if(!mpg123_add_string(purl, response->p+10)) return FALSE; - - debug1(" purl: %s", purl->p); - debug1("old request_url: %s", request_url->p); - - return TRUE; -} - -int win32_net_http_open(const char* url, struct httpdata *hd) -{ - mpg123_string purl, host, port, path; - mpg123_string request, response, request_url; - mpg123_string httpauth1; - ws.local_socket = SOCKET_ERROR; - int oom = 0; - int relocate, numrelocs = 0; - int got_location = FALSE; - /* - workaround for http://www.global24music.com/rautemusik/files/extreme/isdn.pls - this site's apache gives me a relocation to the same place when I give the port in Host request field - for the record: Apache/2.0.51 (Fedora) - */ - int try_without_port = 0; - mpg123_init_string(&purl); - mpg123_init_string(&host); - mpg123_init_string(&port); - mpg123_init_string(&path); - mpg123_init_string(&request); - mpg123_init_string(&response); - mpg123_init_string(&request_url); - mpg123_init_string(&httpauth1); - - /* Get initial info for proxy server. Once. */ - if(hd->proxystate == PROXY_UNKNOWN && !proxy_init(hd)) goto exit; - - if(!translate_url(url, &purl)){ oom=1; goto exit; } - - /* Don't confuse the different auth strings... */ - if(!split_url(&purl, &httpauth1, NULL, NULL, NULL) ){ oom=1; goto exit; } - - /* "GET http://" 11 - * " HTTP/1.0\r\nUser-Agent: /\r\n" - * 26 + PACKAGE_NAME + PACKAGE_VERSION - * accept header + accept_length() - * "Authorization: Basic \r\n" 23 - * "\r\n" 2 - * ... plus the other predefined header lines - */ - /* Just use this estimate as first guess to reduce malloc calls in string library. */ - { - size_t length_estimate = 62 + strlen(PACKAGE_NAME) + strlen(PACKAGE_VERSION) - + accept_length() + strlen(CONN_HEAD) + strlen(icy_yes) + purl.fill; - if( !mpg123_grow_string(&request, length_estimate) - || !mpg123_grow_string(&response,4096) ) - { - oom=1; goto exit; - } - } - - do - { - /* Storing the request url, with http:// prepended if needed. */ - /* used to be url here... seemed wrong to me (when loop advanced...) */ - if(strncasecmp(purl.p, "http://", 7) != 0) mpg123_set_string(&request_url, "http://"); - else mpg123_set_string(&request_url, ""); - - mpg123_add_string(&request_url, purl.p); - - if(!split_url(&purl, NULL, &host, &port, &path)){ oom=1; goto exit; } - if (hd->proxystate >= PROXY_HOST) - { - /* We will connect to proxy, full URL goes into the request. */ - if( !mpg123_set_string(&request, "GET ") - || !mpg123_add_string(&request, request_url.p) ) - { - oom=1; goto exit; - } - } - else - { - /* We will connect to the host from the URL and only the path goes into the request. */ - if( !mpg123_set_string(&request, "GET ") - || !mpg123_add_string(&request, path.p) ) - { - oom=1; goto exit; - } - } - - if(!fill_request(&request, &host, &port, &httpauth1, &try_without_port)){ oom=1; goto exit; } - - httpauth1.fill = 0; /* We use the auth data from the URL only once. */ - if (hd->proxystate >= PROXY_HOST) - { - if( !mpg123_copy_string(&hd->proxyhost, &host) - || !mpg123_copy_string(&hd->proxyport, &port) ) - { - oom=1; goto exit; - } - } - debug2("attempting to open_connection to %s:%s", host.p, port.p); - win32_net_open_connection(&host, &port); - if(ws.local_socket == SOCKET_ERROR) - { - error1("Unable to establish connection to %s", host.fill ? host.p : ""); - goto exit; - } - debug("win32_net_open_connection succeed"); -#define http_failure win32_net_close(ws.local_socket); ws.local_socket=SOCKET_ERROR; goto exit; - - if(param.verbose > 2) fprintf(stderr, "HTTP request:\n%s\n",request.p); - if(!win32_net_writestring(ws.local_socket, &request)){ http_failure; } - debug("Skipping fdopen for WSA sockets"); - relocate = FALSE; - /* Arbitrary length limit here... */ -#define safe_readstring \ - win32_net_readstring(&response, SIZE_MAX/16, -1); \ - if(response.fill > SIZE_MAX/16) /* > because of appended zero. */ \ - { \ - error("HTTP response line exceeds max. length"); \ - http_failure; \ - } \ - else if(response.fill == 0) \ - { \ - error("readstring failed"); \ - http_failure; \ - } \ - if(param.verbose > 2) fprintf(stderr, "HTTP in: %s", response.p); - safe_readstring; - - { - char *sptr; - if((sptr = strchr(response.p, ' '))) - { - if(response.fill > sptr-response.p+2) - switch (sptr[1]) - { - case '3': - relocate = TRUE; - case '2': - break; - default: - fprintf (stderr, "HTTP request failed: %s", sptr+1); /* '\n' is included */ - http_failure; - } - else{ error("Too short response,"); http_failure; } - } - } - - /* If we are relocated, we need to look out for a Location header. */ - got_location = FALSE; - - do - { - safe_readstring; /* Think about that: Should we really error out when we get nothing? Could be that the server forgot the trailing empty line... */ - if (!strncasecmp(response.p, "Location: ", 10)) - { /* It is a redirection! */ - if(!win32_net_resolve_redirect(&response, &request_url, &purl)){ oom=1, http_failure; } - - if(!strcmp(purl.p, request_url.p)) - { - warning("relocated to very same place! trying request again without host port"); - try_without_port = 1; - } - got_location = TRUE; - } - else - { /* We got a header line (or the closing empty line). */ - char *tmp; - debug1("searching for header values... %s", response.p); - /* Not sure if I want to bail out on error here. */ - /* Also: What text encoding are these strings in? Doesn't need to be plain ASCII... */ - get_header_string(&response, "content-type", &hd->content_type); - get_header_string(&response, "icy-name", &hd->icy_name); - get_header_string(&response, "icy-url", &hd->icy_url); - - /* watch out for icy-metaint */ - if((tmp = get_header_val("icy-metaint", &response))) - { - hd->icy_interval = (off_t) atol(tmp); /* atoll ? */ - debug1("got icy-metaint %li", (long int)hd->icy_interval); - } - } - } while(response.p[0] != '\r' && response.p[0] != '\n'); - if (relocate) { win32_net_close(ws.local_socket); ws.local_socket=SOCKET_ERROR; } - } while(relocate && got_location && purl.fill && numrelocs++ < HTTP_MAX_RELOCATIONS); - if(relocate) - { - if(!got_location) - error("Server meant to redirect but failed to provide a location!"); - else - error1("Too many HTTP relocations (%i).", numrelocs); - - http_failure; - } - -exit: /* The end as well as the exception handling point... */ - if(oom) error("Apparently, I ran out of memory or had some bad input data..."); - - mpg123_free_string(&purl); - mpg123_free_string(&host); - mpg123_free_string(&port); - mpg123_free_string(&path); - mpg123_free_string(&request); - mpg123_free_string(&response); - mpg123_free_string(&request_url); - mpg123_free_string(&httpauth1); - if (ws.local_socket == SOCKET_ERROR || oom) - return -1; - else - return 1; -} -#else -int win32_net_http_open(const char* url, struct httpdata *hd) -{ - return -1; -} -#endif /*WANT_WIN32_SOCKETS */ diff --git a/src/win32_support.h b/src/win32_support.h index 1c797de..498d7e6 100755 --- a/src/win32_support.h +++ b/src/win32_support.h @@ -9,7 +9,6 @@ #include "config.h" #include "mpg123.h" -#include "httpget.h" #ifdef HAVE_WINDOWS_H #define WIN32_LEAN_AND_MEAN 1 @@ -32,15 +31,18 @@ Note: Do not treat return values as valid file/socket handles, they only indicate success/failure. file descriptors are ignored, only the local ws.local_socket is used for storing socket handle, so the socket handle is always associated with the last call to win32_net_http_open + +TODO: Move the socket descriptor/state struct into streamdump.c, which wraps all network +connections. Stored in in nh->parts, it enables multiple sockets being opened. */ /** * Opens an http URL - * @param[in] url URL to open - * @param[out] hd http data info + * @param[in] host to connect to + * @param[in] port to use * @return -1 for failure, 1 for success */ -int win32_net_http_open(const char* url, struct httpdata *hd); +int win32_net_open_connection(mpg123_string *host, mpg123_string *port); /** * Reads from network socket @@ -61,13 +63,12 @@ ssize_t win32_net_read (int fildes, void *buf, size_t nbyte); ssize_t win32_net_write (int fildes, const void *buf, size_t nbyte); /** - * Similar to fgets - get a string from a stream - * @param[out] s buffer to Write to - * @param[in] n bytes of data to read. - * @param[in] stream ignored for compatiblity, last open connection is used. - * @return pointer to s if successful, NULL if failture + * Writes a whole mpg123_string to the network socket + * @param[in] filedes Value is ignored, last open connection is used. + * @param[in] string the string to write + * @return TRUE if successful, FALS on error */ -char *win32_net_fgets(char *s, int n, int stream); +int win32_net_writestring (int filedes, mpg123_string *string); /** * Initialize Winsock 2.2. @@ -84,12 +85,6 @@ void win32_net_deinit (void); * @param[in] sock value is ignored. */ void win32_net_close (int sock); - -/** - * Set reader callback for mpg123_open_fd - * @param[in] fr pointer to a mpg123_handle struct. - */ -void win32_net_replace (mpg123_handle *fr); #endif #ifdef WANT_WIN32_UNICODE