mpg123-1.30.0

This commit is contained in:
Ozkan Sezer
2022-06-28 07:10:00 +03:00
parent 01b6013145
commit c46daebce1
56 changed files with 3497 additions and 1035 deletions

20
INSTALL
View File

@@ -5,24 +5,27 @@ mpg123 install hints
You really need:
- a C compiler; we try to keep the code ANSI C89/ISO C90 compatible
gcc from 2.95 on should work, others, too - please report any issues
Actually, we have a confirmed working build (svn trunk leading to
release 0.67) on SunOS 4.1.4 with gcc-2.7.0 .
- a C99 compiler (moderate C99 support)
- an (UNIX-like) operating system with standard tools; MinGW32 and
Cygwin are working for Microsoft Windows, too. We also have users happily
on OS/2.
- For the library only, you may get lucky with MSVC++ using the project
files under ports/
- For the library only, you may get lucky with MSVC++ using CMake and
ports/cmake as source directory. You can also use CMake on other
platforms for a full build, but its main purpose is for portability
where autotools don't do the trick.
- For other exotic platforms, also see ports/
- If building from direct SCM checkout, you need GNU autotools installed
(see below).
(see developer build below).
You want:
- working assembler (recent GNU binutils) if using certain CPU
optimizations
- headers and lib for certain audio output drivers (libasound for alsa,
sdl for sdl...)
@@ -31,10 +34,11 @@ You want:
There is one main supported way to get your mpg123 installation
consisting of
a) the mpg123, mpg123-strip, out123 program binaries
a) the mpg123, mpg123-strip, mpg123-id3dump, out123 program binaries
- with libmpg123, libout123, and libsyn123 as shared libraries or
statically linked
- with audio output plugins for libout123, or one statically linked
b) man pages
(you may want to copy some of the documentation - README, etc - to

View File

@@ -372,14 +372,23 @@ check_PROGRAMS = src/tests/decode_fixed$(EXEEXT) \
@HAVE_MODULES_TRUE@am__append_96 = src/libout123/module.c
@HAVE_MODULES_FALSE@am__append_97 = src/libout123/legacy_module.c
@WIN32_CODES_TRUE@am__append_98 = \
@WIN32_CODES_TRUE@ src/win32_support.c \
@WIN32_CODES_TRUE@ src/win32_net.c
@WIN32_CODES_TRUE@am__append_99 = \
@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
@WIN32_CODES_TRUE@am__append_100 = \
@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 = \
@WIN32_CODES_TRUE@ src/win32_support.c
@WIN32_CODES_TRUE@am__append_110 = \
@WIN32_CODES_TRUE@ src/win32_support.c
subdir = .
@@ -1112,10 +1121,18 @@ am__src_mpg123_SOURCES_DIST = src/audio.c src/audio.h src/common.c \
src/genre.c src/mpg123.c src/mpg123app.h src/metaprint.c \
src/metaprint.h src/local.h src/local.c src/playlist.c \
src/playlist.h src/streamdump.h src/streamdump.c src/term.c \
src/term.h src/win32_support.h src/win32_support.c \
src/win32_net.c
@WIN32_CODES_TRUE@am__objects_70 = src/win32_support.$(OBJEXT) \
@WIN32_CODES_TRUE@ src/win32_net.$(OBJEXT)
src/term.h src/terms.h src/win32_support.h src/term_posix.c \
src/term_win32.c src/term_none.c src/net123.h \
src/net123_exec.c src/net123_winhttp.c src/net123_wininet.c \
src/win32_support.c src/win32_net.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_src_mpg123_OBJECTS = src/audio.$(OBJEXT) src/common.$(OBJEXT) \
src/sysutil.$(OBJEXT) src/control_generic.$(OBJEXT) \
src/equalizer.$(OBJEXT) src/getlopt.$(OBJEXT) \
@@ -1123,19 +1140,22 @@ am_src_mpg123_OBJECTS = src/audio.$(OBJEXT) src/common.$(OBJEXT) \
src/genre.$(OBJEXT) src/mpg123.$(OBJEXT) \
src/metaprint.$(OBJEXT) src/local.$(OBJEXT) \
src/playlist.$(OBJEXT) src/streamdump.$(OBJEXT) \
src/term.$(OBJEXT) $(am__objects_70)
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)
src_mpg123_OBJECTS = $(am_src_mpg123_OBJECTS)
am__DEPENDENCIES_1 =
src_mpg123_DEPENDENCIES = src/compat/libcompat.la \
src/libmpg123/libmpg123.la src/libout123/libout123.la \
src/libsyn123/libsyn123.la
src/libsyn123/libsyn123.la $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
src_mpg123_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(src_mpg123_LDFLAGS) $(LDFLAGS) -o $@
am__src_mpg123_id3dump_SOURCES_DIST = src/mpg123-id3dump.c \
src/getlopt.c src/getlopt.h src/win32_support.c
@WIN32_CODES_TRUE@am__objects_71 = src/win32_support.$(OBJEXT)
am_src_mpg123_id3dump_OBJECTS = src/mpg123-id3dump.$(OBJEXT) \
src/getlopt.$(OBJEXT) $(am__objects_71)
src/getlopt.$(OBJEXT) $(am__objects_76)
src_mpg123_id3dump_OBJECTS = $(am_src_mpg123_id3dump_OBJECTS)
src_mpg123_id3dump_DEPENDENCIES = src/compat/libcompat.la \
src/libmpg123/libmpg123.la
@@ -1150,7 +1170,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_71)
$(am__objects_76)
src_out123_OBJECTS = $(am_src_out123_OBJECTS)
src_out123_DEPENDENCIES = src/compat/libcompat.la \
src/libsyn123/libsyn123.la src/libout123/libout123.la
@@ -1220,11 +1240,15 @@ am__depfiles_remade = src/$(DEPDIR)/audio.Po src/$(DEPDIR)/common.Po \
src/$(DEPDIR)/getlopt.Po src/$(DEPDIR)/httpget.Po \
src/$(DEPDIR)/local.Po src/$(DEPDIR)/metaprint.Po \
src/$(DEPDIR)/mpg123-id3dump.Po src/$(DEPDIR)/mpg123-strip.Po \
src/$(DEPDIR)/mpg123.Po src/$(DEPDIR)/out123.Po \
src/$(DEPDIR)/mpg123.Po src/$(DEPDIR)/net123_exec.Po \
src/$(DEPDIR)/net123_winhttp.Po \
src/$(DEPDIR)/net123_wininet.Po src/$(DEPDIR)/out123.Po \
src/$(DEPDIR)/playlist.Po src/$(DEPDIR)/resolver.Po \
src/$(DEPDIR)/streamdump.Po src/$(DEPDIR)/sysutil.Po \
src/$(DEPDIR)/term.Po src/$(DEPDIR)/win32_net.Po \
src/$(DEPDIR)/win32_support.Po src/compat/$(DEPDIR)/compat.Plo \
src/$(DEPDIR)/term.Po src/$(DEPDIR)/term_none.Po \
src/$(DEPDIR)/term_posix.Po src/$(DEPDIR)/term_win32.Po \
src/$(DEPDIR)/win32_net.Po src/$(DEPDIR)/win32_support.Po \
src/compat/$(DEPDIR)/compat.Plo \
src/compat/$(DEPDIR)/compat_dl.Plo \
src/compat/$(DEPDIR)/compat_str.Plo \
src/libmpg123/$(DEPDIR)/calctables.Po \
@@ -2001,12 +2025,12 @@ EXTRA_DIST = src/tests/testtext.sh src/tests/decode_fixed.sh \
doc/ROAD_TO_LGPL doc/TODO doc/LICENSE doc/THANKS doc/ACCURACY \
doc/LARGEFILE doc/libmpg123_speed.txt doc/doxyhead.xhtml \
doc/doxyfoot.xhtml doc/doxy_examples.c doc/doxygen.conf \
doc/examples/mpg123_to_out123.c doc/examples/scan.c \
doc/examples/mpglib.c doc/examples/id3dump.c \
doc/examples/feedseek.c 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 \
doc/windows-notes.html doc/examples/mpg123_to_out123.c \
doc/examples/scan.c doc/examples/mpglib.c \
doc/examples/id3dump.c doc/examples/feedseek.c \
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/cmake/search_libs.cmake \
ports/cmake/cmake/read_api_version.cmake \
@@ -2854,13 +2878,10 @@ src_libsyn123_libsyn123_la_SOURCES = \
src/libsyn123/filter.c \
src/libsyn123/sampleconv.c
src_mpg123_LDADD = \
src/compat/libcompat.la \
src/libmpg123/libmpg123.la \
src/libout123/libout123.la \
src/libsyn123/libsyn123.la \
@PROG_LIBS@
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)
src_mpg123_LDFLAGS = @EXEC_LT_LDFLAGS@
src_out123_LDADD = \
src/compat/libcompat.la \
@@ -2888,15 +2909,18 @@ src_mpg123_SOURCES = src/audio.c src/audio.h src/common.c src/common.h \
src/genre.c src/mpg123.c src/mpg123app.h src/metaprint.c \
src/metaprint.h src/local.h src/local.c src/playlist.c \
src/playlist.h src/streamdump.h src/streamdump.c src/term.c \
src/term.h src/win32_support.h $(am__append_98)
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)
# 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_99)
src/win32_support.h $(am__append_109)
src_mpg123_id3dump_SOURCES = src/mpg123-id3dump.c src/getlopt.c \
src/getlopt.h $(am__append_100)
src/getlopt.h $(am__append_110)
src_mpg123_strip_SOURCES = \
src/mpg123-strip.c \
src/getlopt.c \
@@ -3689,6 +3713,18 @@ src/playlist.$(OBJEXT): src/$(am__dirstamp) \
src/streamdump.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/term.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
src/term_posix.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/term_win32.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/term_none.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/net123_exec.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/net123_winhttp.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/net123_wininet.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/win32_support.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/win32_net.$(OBJEXT): src/$(am__dirstamp) \
@@ -3815,12 +3851,18 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/mpg123-id3dump.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/mpg123-strip.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/mpg123.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/net123_exec.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/net123_winhttp.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/net123_wininet.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/out123.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/playlist.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/resolver.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/streamdump.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sysutil.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/term.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/term_none.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/term_posix.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/term_win32.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/win32_net.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/win32_support.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@src/compat/$(DEPDIR)/compat.Plo@am__quote@ # am--include-marker
@@ -5342,12 +5384,18 @@ distclean: distclean-am
-rm -f src/$(DEPDIR)/mpg123-id3dump.Po
-rm -f src/$(DEPDIR)/mpg123-strip.Po
-rm -f src/$(DEPDIR)/mpg123.Po
-rm -f src/$(DEPDIR)/net123_exec.Po
-rm -f src/$(DEPDIR)/net123_winhttp.Po
-rm -f src/$(DEPDIR)/net123_wininet.Po
-rm -f src/$(DEPDIR)/out123.Po
-rm -f src/$(DEPDIR)/playlist.Po
-rm -f src/$(DEPDIR)/resolver.Po
-rm -f src/$(DEPDIR)/streamdump.Po
-rm -f src/$(DEPDIR)/sysutil.Po
-rm -f src/$(DEPDIR)/term.Po
-rm -f src/$(DEPDIR)/term_none.Po
-rm -f src/$(DEPDIR)/term_posix.Po
-rm -f src/$(DEPDIR)/term_win32.Po
-rm -f src/$(DEPDIR)/win32_net.Po
-rm -f src/$(DEPDIR)/win32_support.Po
-rm -f src/compat/$(DEPDIR)/compat.Plo
@@ -5590,12 +5638,18 @@ maintainer-clean: maintainer-clean-am
-rm -f src/$(DEPDIR)/mpg123-id3dump.Po
-rm -f src/$(DEPDIR)/mpg123-strip.Po
-rm -f src/$(DEPDIR)/mpg123.Po
-rm -f src/$(DEPDIR)/net123_exec.Po
-rm -f src/$(DEPDIR)/net123_winhttp.Po
-rm -f src/$(DEPDIR)/net123_wininet.Po
-rm -f src/$(DEPDIR)/out123.Po
-rm -f src/$(DEPDIR)/playlist.Po
-rm -f src/$(DEPDIR)/resolver.Po
-rm -f src/$(DEPDIR)/streamdump.Po
-rm -f src/$(DEPDIR)/sysutil.Po
-rm -f src/$(DEPDIR)/term.Po
-rm -f src/$(DEPDIR)/term_none.Po
-rm -f src/$(DEPDIR)/term_posix.Po
-rm -f src/$(DEPDIR)/term_win32.Po
-rm -f src/$(DEPDIR)/win32_net.Po
-rm -f src/$(DEPDIR)/win32_support.Po
-rm -f src/compat/$(DEPDIR)/compat.Plo

46
NEWS
View File

@@ -1,3 +1,49 @@
1.30.0
------
- build:
-- Use dummy as default module when no other outputs are enabled. This also
fixes a non-module build with just the dummy (bug 333).
-- Use CMAKE_CURRENT_SOURCE_DIR in CMake build to help nested use (bug 335).
-- some updates for OS/2 support (fixing up stdin playing, for example)
- mpg123:
-- new network backend using external tools/libraries to also support HTTPS
-- old network backend changed to use h_addr_list[0] instead of h_addr
-- terminal control keys now case-sensitive (fixing smal/big pitch controls)
-- additional terminal control keys for simple equalizer control (A/a for bass,
J/j for mids, N/n for treble, e for reset, E for printout)
-- terminal volume control now in decibel steps and bounded to +/- 60 dB
-- terminal control now also with audio from stdin (bug 338) via
/dev/tty or ctermid()
-- terminal control also available for OS/2 and Windows platforms
-- re-print tag info on decrease of terminal width for a bit less mess
-- always print an empty line after tag info for cleaner appearance
-- print lyrics also to stderr
-- remote control API v10 with "@P 3" as additonal message on track end
-- also added PROGRESS command as opposite of SILENCE
-- fix some verbosity, tweak help for --icy-interval
-- added --auth-file
-- also obscure argument to --auth for others
-- Cygwin/MinGW: Provide _win32_utf8_wide and _win32_wide_utf8 unconditionally.
It is needed by the WASAPI plugins, the underlying conversion functions
should be present since Windows 2000. Fixes WASAPI support on Cygwin.
Also needed for new network code.
- libout123:
-- pulse: initialize more error codes to avoid bogus error messages
-- os2: considerable fixup for proper writes of full buffers avoiding
nasty effects from the ... special audio system, more cleanup still
nice-to-have, but still lacking
1.29.4
------
- libmpg123:
-- Saturate reader file position at off_t limit to satisfy
undefined behaviour checkers.
-- Avoid harmless unitialized value in ID3v1 check (filepos, later being
set before actual use).
- libout123:
-- Build fix for win32_wasapi output for predefined _WIN32_WINNT (bug 329),
thanks to Vincent Torri.
1.29.3
------
- libmpg123: Catch more NULL pointer arguments in LFS wrappers

View File

@@ -1,5 +1,7 @@
Changes in libmpg123 libtool interface versions...
47.0.47 - Added mpg123_eq_bands(), mpg123_eq_change() and mpg123_volume_change_db().
46.0.46
- Functions mpg123_init() and mpg123_exit() are really no-ops now.
There is no need to call them, and no harm done calling them in

501
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for mpg123 1.29.3.
# Generated by GNU Autoconf 2.69 for mpg123 1.30.0.
#
# Report bugs to <maintainer@mpg123.org>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mpg123'
PACKAGE_TARNAME='mpg123'
PACKAGE_VERSION='1.29.3'
PACKAGE_STRING='mpg123 1.29.3'
PACKAGE_VERSION='1.30.0'
PACKAGE_STRING='mpg123 1.30.0'
PACKAGE_BUGREPORT='maintainer@mpg123.org'
PACKAGE_URL=''
@@ -641,6 +641,20 @@ LIBOUT123_LIBS
LIBSYN123_LIBS
LIBMPG123_LIBS
PROG_LIBS
TERM_WIN32_FALSE
TERM_WIN32_TRUE
TERM_NONE_FALSE
TERM_NONE_TRUE
TERM_POSIX_FALSE
TERM_POSIX_TRUE
NET123_WININET_FALSE
NET123_WININET_TRUE
NET123_WINHTTP_FALSE
NET123_WINHTTP_TRUE
NET123_EXEC_FALSE
NET123_EXEC_TRUE
NETWORK_WINSOCK_FALSE
NETWORK_WINSOCK_TRUE
WIN32_CODES_FALSE
WIN32_CODES_TRUE
BUILD_BUFFER_FALSE
@@ -1060,8 +1074,6 @@ enable_xdebug
enable_nagging
enable_gapless
enable_fifo
enable_ipv6
enable_network
enable_id3v2
enable_string
enable_icy
@@ -1094,6 +1106,9 @@ with_seektable
enable_largefile
enable_lfs_alias
enable_feature_report
enable_ipv6
enable_network
with_network
'
ac_precious_vars='build_alias
host_alias
@@ -1668,7 +1683,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.29.3 to adapt to many kinds of systems.
\`configure' configures mpg123 1.30.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1739,7 +1754,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of mpg123 1.29.3:";;
short | recursive ) echo "Configuration of mpg123 1.30.0:";;
esac
cat <<\_ACEOF
@@ -1764,8 +1779,6 @@ Optional Features:
--enable-nagging=no/yes turn on GCC's pedantic nagging with error on warnings, does not include --enable-debug anymore
--enable-gapless=no/yes turn on gapless (enabled per default)
--enable-fifo=no/yes FIFO support for control interface (auto-enabled on linux)
--enable-ipv6=no/yes IPv6 support (actually any protocol your libc does with getaddrinfo)
--enable-network=no/yes network support (http streams / webradio)
--disable-id3v2=no/yes no ID3v2 parsing
--disable-string=no/yes no string API (this will disable ID3v2; main mpg123 won't build anymore)
--disable-icy=no/yes no ICY metainfo parsing/conversion (main mpg123 won't build!)
@@ -1793,6 +1806,8 @@ Optional Features:
--disable-largefile omit support for large files
--disable-lfs-alias disable alias wrappers for largefile bitness (mpg123_seek_32 or mpg123_seek_64 in addition to mpg123_seek, or the other way around; It is a mess, do not play with this!)
--disable-feature_report Disable feature report function
--enable-ipv6=no/yes IPv6 support in internal network stack
--enable-network=no/yes network support (http streams / webradio), if available (overruled by --with-network!)
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@@ -1875,6 +1890,9 @@ Optional Packages:
--with-seektable=<size> choose size of seek index table (0 disables it), default 1000
--with-network=<type> Available options, depending on platform, are auto,
none, internal, winhttp, wininet, and exec (wget or
curl binaries).
Some influential environment variables:
CC C compiler command
@@ -1970,7 +1988,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
mpg123 configure 1.29.3
mpg123 configure 1.30.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2576,7 +2594,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.29.3, which was
It was created by mpg123 $as_me 1.30.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2925,11 +2943,11 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
API_VERSION=46
LIB_PATCHLEVEL=7
API_VERSION=47
LIB_PATCHLEVEL=0
OUTAPI_VERSION=4
OUTLIB_PATCHLEVEL=3
OUTLIB_PATCHLEVEL=4
SYNAPI_VERSION=1
SYNLIB_PATCHLEVEL=4
@@ -3535,7 +3553,7 @@ fi
# Define the identity of the package.
PACKAGE='mpg123'
VERSION='1.29.3'
VERSION='1.30.0'
cat >>confdefs.h <<_ACEOF
@@ -14401,42 +14419,6 @@ else
fi
# Check whether --enable-ipv6 was given.
if test "${enable_ipv6+set}" = set; then :
enableval=$enable_ipv6;
if test "x$enableval" = xyes
then
ipv6="enabled"
else
ipv6="disabled"
fi
else
ipv6="auto"
fi
# Check whether --enable-network was given.
if test "${enable_network+set}" = set; then :
enableval=$enable_network;
if test "x$enableval" = xyes
then
network="enabled"
else
network="disabled"
fi
else
network="auto"
fi
id3v2=enabled
@@ -16039,6 +16021,7 @@ 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; }
@@ -16077,6 +16060,7 @@ cat >>confdefs.h <<_ACEOF
#define HAVE_TERMIOS 1
_ACEOF
term_type=posix
fi
for ac_func in random
@@ -16173,6 +16157,77 @@ fi
done
for ac_func in fork execvp
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"
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
have_fork=yes
else
have_fork=no; break
fi
done
for ac_func in ctermid
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"
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
fi
done
#AC_CHECK_FUNCS( _setmode setmode )
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
_setmode(STDIN_FILENO, _O_BINARY);
_setmode(STDOUT_FILENO, _O_TEXT);
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
$as_echo "#define HAVE__SETMODE 1" >>confdefs.h
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
setmode(STDIN_FILENO, O_BINARY);
setmode(STDOUT_FILENO, O_TEXT);
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
$as_echo "#define HAVE_SETMODE 1" >>confdefs.h
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
# locale headers
for ac_header in locale.h langinfo.h wchar.h wctype.h
@@ -16189,7 +16244,7 @@ fi
done
# Headers for network (http) stuff
network_type=Unknown
network_internal=unknown
for ac_header in netdb.h sys/param.h sys/socket.h netinet/in.h arpa/inet.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
@@ -16209,7 +16264,7 @@ if test "x$ac_cv_header_netdb_h" = "xyes" &&
test "x$ac_cv_header_netinet_in_h" = "xyes" &&
test "x$ac_cv_header_arpa_inet_h" = "xyes"; then
have_network=yes
network_type=Posix
network_internal=posix
else
have_network=no
fi
@@ -16494,54 +16549,20 @@ ADD_CPPFLAGS="$sys_cppflags"
ADD_LDFLAGS=""
LIBS="$LIBS"
# Consider moving that stuff.
ac_fn_c_check_header_mongrel "$LINENO" "os2.h" "ac_cv_header_os2_h" "$ac_includes_default"
# Remove that if it is settled that tcsetattr on OS/2 is unsalvageable anyway.
# The only user of os2.h is the output module.
for ac_header in os2.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "os2.h" "ac_cv_header_os2_h" "$ac_includes_default"
if test "x$ac_cv_header_os2_h" = xyes; then :
ADD_CPPFLAGS="$ADD_CPPFLAGS -DOS2"
fi
# On OS/2, we need to link to os2term to make terminal control actually work.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tcsetattr in -los2term" >&5
$as_echo_n "checking for tcsetattr in -los2term... " >&6; }
if ${ac_cv_lib_os2term_tcsetattr+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-los2term $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 tcsetattr ();
int
main ()
{
return tcsetattr ();
;
return 0;
}
cat >>confdefs.h <<_ACEOF
#define HAVE_OS2_H 1
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_os2term_tcsetattr=yes
else
ac_cv_lib_os2term_tcsetattr=no
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_os2term_tcsetattr" >&5
$as_echo "$ac_cv_lib_os2term_tcsetattr" >&6; }
if test "x$ac_cv_lib_os2term_tcsetattr" = xyes; then :
ADD_LDFLAGS="$ADD_LDFLAGS -los2term"
fi
done
# If debugging is enabled, just enable debugging symbols.
# All other stuff enters nagging territory.
@@ -17047,7 +17068,10 @@ output_modules=
check_forced=no
check_failed=no
if test "x$with_audio" != "x"; then
check_modules="`echo $with_audio|tr , ' '` dummy"
check_modules=`echo $with_audio|tr , ' '`
if ! echo "$check_modules" | grep -qw dummy; then
check_modules="$check_modules dummy"
fi
echo "Limiting outputs to build according to your preference: $check_modules"
check_forced=yes
fi
@@ -18298,6 +18322,9 @@ done
;;
os2)
OS2_LIBS="-lcx -lmmpm2"
OS2_CFLAGS="-idirafter /@unixroot/usr/include/os2tk45"
oldcflags="$CFLAGS"
CFLAGS="$CFLAGS $OS2_CFLAGS"
for ac_header in os2.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "os2.h" "ac_cv_header_os2_h" "$ac_includes_default"
@@ -18319,6 +18346,7 @@ done
for ac_header in os2me.h
do :
ac_fn_c_check_header_compile "$LINENO" "os2me.h" "ac_cv_header_os2me_h" "#define INCL_OS2MM
#undef VERSION
#define INCL_DOS
#define INCL_VIO
#define INCL_KBD
@@ -18343,6 +18371,7 @@ done
else
check_failed=yes
fi
CFLAGS="$oldcflags"
;;
# from here on only forced tests, untested code
hp)
@@ -18760,6 +18789,15 @@ fi
default_output_module=`first_word $default_output_modules`
# Without actual modules, there is only the builtin one.
if test x"$modules" = xdisabled; then
# Module-less build needs _some_ default module.
if test -z "$default_output_module"; then
default_output_module=dummy
fi
default_output_modules=$default_output_module
fi
# Setup the static build.
# The conditionals always need to be defined by configure, even if
# HAVE_MODULES is FALSE!
@@ -18964,10 +19002,6 @@ else
fi
# Without actual modules, there is only the builtin one.
if test x"$modules" = xdisabled; then
default_output_modules=$default_output_module
fi
default_modstring=`echo "$default_output_modules"|tr ' ' ,`
cat >>confdefs.h <<_ACEOF
@@ -19060,21 +19094,14 @@ _ACEOF
# Check if we want Unicode for Win32. Cygwin and Midipix does not need _wopen
if test "x$ac_cv_header_windows_h" = xyes &&
test "x$host_os" != xcygwin &&
test "x$host_os" != xmidipix; then
win32_specific_codes=enabled
else
win32_specific_codes=disabled
fi
COMPAT_LIBS=
win32_unicode=unneeded
win32_sockets=disabled
win32_sockets_working=no
win32_wide_working=no
win32_winver_bump=no
COMPAT_LIBS=
### mingw.org may not work properly for newer APIs
case $host_os in
*mingw*)
@@ -19096,6 +19123,11 @@ fi
;;
esac
# enable win32 code
if test "x$ac_cv_header_windows_h" = xyes -a "x$host_os" != xcygwin -a "x$host_os" != xmidipix; then
win32_specific_codes=enabled
fi
if test "x$win32_specific_codes" = xenabled; then
#### Check for Wide functions
ac_fn_c_check_func "$LINENO" "_wopen" "ac_cv_func__wopen"
@@ -19202,7 +19234,7 @@ done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we want Win32 sockets" >&5
$as_echo_n "checking if we want Win32 sockets... " >&6; }
if test "x$win32_sockets" = "xenabled" && test "x$network" != "xdisabled"; then
if test "x$win32_sockets" = "xenabled"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if winsock2 API is available" >&5
@@ -19261,17 +19293,14 @@ rm -f core conftest.err conftest.$ac_objext \
if test "x$win32_sockets_working" = "xyes"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define WANT_WIN32_SOCKETS 1" >>confdefs.h
network_type=Winsock2
network_internal=winsock2
have_network=yes
have_ipv6=yes
else
LIBS="$wsoldlibs"
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Please update your headers to support winsock 2.2." >&5
$as_echo "$as_me: WARNING: Please update your headers to support winsock 2.2." >&2;}
fi
LIBS="$wsoldlibs"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
@@ -19436,6 +19465,123 @@ $as_echo "#define EOVERFLOW EFBIG" >>confdefs.h
fi
# old network choice
# Check whether --enable-ipv6 was given.
if test "${enable_ipv6+set}" = set; then :
enableval=$enable_ipv6;
if test "x$enableval" = xyes
then
ipv6="enabled"
else
ipv6="disabled"
fi
else
ipv6="auto"
fi
network_type=auto
# Check whether --enable-network was given.
if test "${enable_network+set}" = set; then :
enableval=$enable_network;
if test "x$enableval" = xyes
then
network_type=auto
else
network_type=disabled
fi
fi
# new network choice
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for preferred network support" >&5
$as_echo_n "checking for preferred network support... " >&6; }
# Check whether --with-network was given.
if test "${with_network+set}" = set; then :
withval=$with_network;
case "$withval" in
exec)
network_type="exec"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: exec" >&5
$as_echo "exec" >&6; }
;;
winhttp)
network_type="winhttp"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: winhttp" >&5
$as_echo "winhttp" >&6; }
;;
wininet)
network_type="wininet"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: wininet" >&5
$as_echo "wininet" >&6; }
;;
internal)
network_type="internal"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: internal" >&5
$as_echo "internal" >&6; }
;;
yes|auto)
network_type="auto"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: auto" >&5
$as_echo "auto" >&6; }
;;
no|none)
network_type="disabled"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
$as_echo "none" >&6; }
;;
*)
as_fn_error $? "Unknown network option \"$withval\"" "$LINENO" 5
;;
esac
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $network_type" >&5
$as_echo "$network_type" >&6; }
fi
if test x$network_type = xauto; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for automatic network support" >&5
$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=winhttp
elif test "x$have_network" = "xyes"; then
network_type="internal"
else
network_type="disabled"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $network_type" >&5
$as_echo "$network_type" >&6; }
fi
# new net123
if test x$network_type != xinternal -a x$network_type != xdisabled; then
$as_echo "#define NET123 1" >>confdefs.h
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
as_fn_error $? "wininet or winhttp is currently only for Windows" "$LINENO" 5
fi
#### Use Win32 support codes
if test "x$win32_specific_codes" = xenabled ; then
WIN32_CODES_TRUE=
@@ -19446,21 +19592,83 @@ else
fi
if test x"$network" = xauto; then
if test x"$have_network" = xyes; then
network=enabled
else
network=disabled
fi
fi
if test x"$ipv6" = xauto; then
if test x"$have_ipv6" = xyes; 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
ipv6=enabled
else
ipv6=disabled
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ipv6" >&5
$as_echo "$ipv6" >&6; }
fi
if test x$network_type = xinternal -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
NETWORK_WINSOCK_TRUE=
NETWORK_WINSOCK_FALSE='#'
else
NETWORK_WINSOCK_TRUE='#'
NETWORK_WINSOCK_FALSE=
fi
if test x$network_type = xexec ; then
NET123_EXEC_TRUE=
NET123_EXEC_FALSE='#'
else
NET123_EXEC_TRUE='#'
NET123_EXEC_FALSE=
fi
if test x$network_type = xwinhttp ; then
NET123_WINHTTP_TRUE=
NET123_WINHTTP_FALSE='#'
else
NET123_WINHTTP_TRUE='#'
NET123_WINHTTP_FALSE=
fi
if test x$network_type = xwininet ; then
NET123_WININET_TRUE=
NET123_WININET_FALSE='#'
else
NET123_WININET_TRUE='#'
NET123_WININET_FALSE=
fi
if test "x$term_type" = xposix ; then
TERM_POSIX_TRUE=
TERM_POSIX_FALSE='#'
else
TERM_POSIX_TRUE='#'
TERM_POSIX_FALSE=
fi
if test "x$term_type" = xnone ; then
TERM_NONE_TRUE=
TERM_NONE_FALSE='#'
else
TERM_NONE_TRUE='#'
TERM_NONE_FALSE=
fi
if test "x$term_type" = xwin32 ; then
TERM_WIN32_TRUE=
TERM_WIN32_FALSE='#'
else
TERM_WIN32_TRUE='#'
TERM_WIN32_FALSE=
fi
if test x"$fifo" = xauto; then
if test x"$have_mkfifo" = xyes; then
@@ -19480,7 +19688,7 @@ $as_echo "$as_me: WARNING: You forced FIFO code while I think there is no mkfif
fi
fi
if test x"$network" = xenabled; then
if test x"$network_type" = xinternal; then
$as_echo "#define NETWORK 1" >>confdefs.h
@@ -20023,6 +20231,34 @@ if test -z "${WIN32_CODES_TRUE}" && test -z "${WIN32_CODES_FALSE}"; then
as_fn_error $? "conditional \"WIN32_CODES\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
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_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
fi
if test -z "${NET123_WINHTTP_TRUE}" && test -z "${NET123_WINHTTP_FALSE}"; then
as_fn_error $? "conditional \"NET123_WINHTTP\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${NET123_WININET_TRUE}" && test -z "${NET123_WININET_FALSE}"; then
as_fn_error $? "conditional \"NET123_WININET\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${TERM_POSIX_TRUE}" && test -z "${TERM_POSIX_FALSE}"; then
as_fn_error $? "conditional \"TERM_POSIX\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${TERM_NONE_TRUE}" && test -z "${TERM_NONE_FALSE}"; then
as_fn_error $? "conditional \"TERM_NONE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${TERM_WIN32_TRUE}" && test -z "${TERM_WIN32_FALSE}"; then
as_fn_error $? "conditional \"TERM_WIN32\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
@@ -20420,7 +20656,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.29.3, which was
This file was extended by mpg123 $as_me 1.30.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -20486,7 +20722,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.29.3
mpg123 config.status 1.30.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -22185,8 +22421,6 @@ fi
echo "
$PACKAGE_NAME $PACKAGE_VERSION
@@ -22195,13 +22429,16 @@ echo "
Compiler Optimization ... $with_optimization
Gapless Support ......... $gapless
Debugging ............... $debugging
Terminal control ........ $term_type
Extreme debugging ....... $xdebugging
Seek table size ......... $seektable
FIFO support ............ $fifo
Buffer .................. $buffer
Network (http streams) .. $network
Network Sockets ......... $network_type
Network (http streams) .. $network_type"
if test x$network_type = xinternal; then
echo " Internal network type ... $network_internal
IPv6 (getaddrinfo) ...... $ipv6"
fi
if test x"$LARGEFILE_BITS" = x; then
echo " File offsets ............ default"
else

View File

@@ -9,16 +9,16 @@ dnl 2.69 at least.
AC_PREREQ([2.69])
dnl ############# Initialisation
AC_INIT([mpg123], [1.29.3], [maintainer@mpg123.org])
AC_INIT([mpg123], [1.30.0], [maintainer@mpg123.org])
dnl Increment API_VERSION when the API gets changes (new functions).
dnl libmpg123
API_VERSION=46
LIB_PATCHLEVEL=7
API_VERSION=47
LIB_PATCHLEVEL=0
dnl libout123
OUTAPI_VERSION=4
OUTLIB_PATCHLEVEL=3
OUTLIB_PATCHLEVEL=4
dnl libsyn123
SYNAPI_VERSION=1
@@ -370,36 +370,6 @@ AC_ARG_ENABLE(fifo,
]
)
AC_ARG_ENABLE(ipv6,
[ --enable-ipv6=[no/yes] IPv6 support (actually any protocol your libc does with getaddrinfo) ],
[
if test "x$enableval" = xyes
then
ipv6="enabled"
else
ipv6="disabled"
fi
],
[
ipv6="auto"
]
)
AC_ARG_ENABLE(network,
[ --enable-network=[no/yes] network support (http streams / webradio) ],
[
if test "x$enableval" = xyes
then
network="enabled"
else
network="disabled"
fi
],
[
network="auto"
]
)
dnl Optional objects list, depends on decoder choice and core feature selection.
dnl Not just for specific decoders anymore...
@@ -1239,11 +1209,13 @@ 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
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
fi
AC_CHECK_FUNCS( random )
@@ -1262,12 +1234,45 @@ AC_CHECK_FUNCS( atoll )
AC_CHECK_FUNCS( mkfifo, [ have_mkfifo=yes ], [ have_mkfifo=no ] )
AC_CHECK_FUNCS( fork execvp, [ have_fork=yes ], [have_fork=no; break] )
AC_CHECK_FUNCS( ctermid )
dnl For Windows and OS/2.
dnl Checking for both the functions as well as the flag symbols.
dnl Taking care with _setmode() being preferred on Windows, and
dnl OS/2 providing _setmode, but not the underscored flags.
#AC_CHECK_FUNCS( _setmode setmode )
AC_LINK_IFELSE( [AC_LANG_SOURCE(
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
_setmode(STDIN_FILENO, _O_BINARY);
_setmode(STDOUT_FILENO, _O_TEXT);
return 0;
} )], [AC_DEFINE( HAVE__SETMODE, 1, [for Win/DOS system with _setmode()] )], [] )
AC_LINK_IFELSE( [AC_LANG_SOURCE(
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
setmode(STDIN_FILENO, O_BINARY);
setmode(STDOUT_FILENO, O_TEXT);
return 0;
} )], [AC_DEFINE( HAVE_SETMODE, 1, [for Win/DOS system with setmode()] )], [] )
dnl ############## Header and Library Checks
# locale headers
AC_CHECK_HEADERS([locale.h langinfo.h wchar.h wctype.h])
# Headers for network (http) stuff
network_type=Unknown
network_internal=unknown
AC_CHECK_HEADERS([netdb.h sys/param.h sys/socket.h netinet/in.h arpa/inet.h])
if test "x$ac_cv_header_netdb_h" = "xyes" &&
test "x$ac_cv_header_sys_param_h" = "xyes" &&
@@ -1275,7 +1280,7 @@ if test "x$ac_cv_header_netdb_h" = "xyes" &&
test "x$ac_cv_header_netinet_in_h" = "xyes" &&
test "x$ac_cv_header_arpa_inet_h" = "xyes"; then
have_network=yes
network_type=Posix
network_internal=posix
else
have_network=no
fi
@@ -1342,10 +1347,9 @@ ADD_CPPFLAGS="$sys_cppflags"
ADD_LDFLAGS=""
LIBS="$LIBS"
# Consider moving that stuff.
AC_CHECK_HEADER([os2.h], [ADD_CPPFLAGS="$ADD_CPPFLAGS -DOS2"])
# On OS/2, we need to link to os2term to make terminal control actually work.
AC_CHECK_LIB([os2term], [tcsetattr], [ADD_LDFLAGS="$ADD_LDFLAGS -los2term"])
# Remove that if it is settled that tcsetattr on OS/2 is unsalvageable anyway.
# The only user of os2.h is the output module.
AC_CHECK_HEADERS([os2.h])
# If debugging is enabled, just enable debugging symbols.
# All other stuff enters nagging territory.
@@ -1675,7 +1679,10 @@ output_modules=
check_forced=no
check_failed=no
if test "x$with_audio" != "x"; then
check_modules="`echo $with_audio|tr , ' '` dummy"
check_modules=`echo $with_audio|tr , ' '`
if ! echo "$check_modules" | grep -qw dummy; then
check_modules="$check_modules dummy"
fi
echo "Limiting outputs to build according to your preference: $check_modules"
check_forced=yes
fi
@@ -1968,6 +1975,9 @@ int main(){
;;
os2)
OS2_LIBS="-lcx -lmmpm2"
OS2_CFLAGS="-idirafter /@unixroot/usr/include/os2tk45"
oldcflags="$CFLAGS"
CFLAGS="$CFLAGS $OS2_CFLAGS"
AC_CHECK_HEADERS([os2.h])
# os2me.h depends on os2.h
# Yes, that way of coding it is ugly.
@@ -1976,6 +1986,7 @@ int main(){
# We mimick exactly the way how the header will be used.
# It seems to be picky...
AC_CHECK_HEADERS([os2me.h], [], [], [#define INCL_OS2MM
#undef VERSION
#define INCL_DOS
#define INCL_VIO
#define INCL_KBD
@@ -1990,6 +2001,7 @@ int main(){
else
check_failed=yes
fi
CFLAGS="$oldcflags"
;;
# from here on only forced tests, untested code
hp)
@@ -2186,6 +2198,15 @@ fi
default_output_module=`first_word $default_output_modules`
# Without actual modules, there is only the builtin one.
if test x"$modules" = xdisabled; then
# Module-less build needs _some_ default module.
if test -z "$default_output_module"; then
default_output_module=dummy
fi
default_output_modules=$default_output_module
fi
# Setup the static build.
# The conditionals always need to be defined by configure, even if
# HAVE_MODULES is FALSE!
@@ -2222,10 +2243,6 @@ AM_CONDITIONAL([BUILD_SGI], [ test "sgi" = $default_output_module ])
AM_CONDITIONAL([BUILD_MINT], [ test "mint" = $default_output_module ])
AM_CONDITIONAL([BUILD_OPENAL], [ test "openal" = $default_output_module ])
# Without actual modules, there is only the builtin one.
if test x"$modules" = xdisabled; then
default_output_modules=$default_output_module
fi
default_modstring=`echo "$default_output_modules"|tr ' ' ,`
AC_DEFINE_UNQUOTED( DEFAULT_OUTPUT_MODULE, "$default_modstring", [The default audio output module(s) to use] )
@@ -2305,21 +2322,14 @@ AC_DEFINE_UNQUOTED(INDEX_SIZE, $seektable, [size of the frame index seek table])
dnl ############## Win32 function checks
# Check if we want Unicode for Win32. Cygwin and Midipix does not need _wopen
if test "x$ac_cv_header_windows_h" = xyes &&
test "x$host_os" != xcygwin &&
test "x$host_os" != xmidipix; then
win32_specific_codes=enabled
else
win32_specific_codes=disabled
fi
COMPAT_LIBS=
win32_unicode=unneeded
win32_sockets=disabled
win32_sockets_working=no
win32_wide_working=no
win32_winver_bump=no
COMPAT_LIBS=
### mingw.org may not work properly for newer APIs
case $host_os in
*mingw*)
@@ -2331,6 +2341,11 @@ case $host_os in
;;
esac
# enable win32 code
if test "x$ac_cv_header_windows_h" = xyes -a "x$host_os" != xcygwin -a "x$host_os" != xmidipix; then
win32_specific_codes=enabled
fi
dnl We do not support non-unicode Windows.
if test "x$win32_specific_codes" = xenabled; then
#### Check for Wide functions
@@ -2390,7 +2405,7 @@ if test "x$win32_specific_codes" = xenabled; then
#### Check for Network functions
AC_CHECK_HEADERS([ws2tcpip.h], [win32_sockets=enabled], [AC_MSG_WARN([Please update your headers to support winsock 2.2.])])
AC_MSG_CHECKING([if we want Win32 sockets])
if test "x$win32_sockets" = "xenabled" && test "x$network" != "xdisabled"; then
if test "x$win32_sockets" = "xenabled"; then
AC_MSG_RESULT([yes])
AC_MSG_CHECKING([if winsock2 API is available])
wsoldlibs="$LIBS"
@@ -2424,14 +2439,13 @@ if test "x$win32_specific_codes" = xenabled; then
fi
if test "x$win32_sockets_working" = "xyes"; then
AC_MSG_RESULT([yes])
AC_DEFINE([WANT_WIN32_SOCKETS], [1], [ Define to use Win32 sockets ])
network_type=Winsock2
network_internal=winsock2
have_network=yes
have_ipv6=yes
else
LIBS="$wsoldlibs"
AC_MSG_WARN([Please update your headers to support winsock 2.2.])
fi
LIBS="$wsoldlibs"
else
AC_MSG_RESULT([no])
fi
@@ -2522,24 +2536,137 @@ int i = (EOVERFLOW) + 0;
AC_MSG_RESULT([$eoverflow_present])
AS_IF([test "x$eoverflow_present" = "xyes"],[],[AC_DEFINE([EOVERFLOW],[EFBIG],[Use EFBIG as substitude for EOVERFLOW, mingw.org may lack the latter])])
# old network choice
AC_ARG_ENABLE(ipv6,
[ --enable-ipv6=[no/yes] IPv6 support in internal network stack ],
[
if test "x$enableval" = xyes
then
ipv6="enabled"
else
ipv6="disabled"
fi
],
[
ipv6="auto"
]
)
dnl make it clear that auto is the default for both enable and with options.
network_type=auto
dnl This is to be kept in sync with --with-network, it is a shortcut that
dnl keep the old semantics of being able to --disable-network support altogether.
dnl The default should match the --with-network default.
AC_ARG_ENABLE(network,
[ --enable-network=[no/yes] network support (http streams / webradio), if available (overruled by --with-network!) ],
[
if test "x$enableval" = xyes
then
network_type=auto
else
network_type=disabled
fi
],
[
]
)
# new network choice
AC_MSG_CHECKING([for preferred network support])
AC_ARG_WITH([network],
[AS_HELP_STRING([--with-network=<type>], [Available options, depending on platform, are auto, none, internal, winhttp, wininet, and exec (wget or curl binaries).])],
[
case "$withval" in
exec)
network_type="exec"
AC_MSG_RESULT([exec])
;;
winhttp)
network_type="winhttp"
AC_MSG_RESULT([winhttp])
;;
wininet)
network_type="wininet"
AC_MSG_RESULT([wininet])
;;
internal)
network_type="internal"
AC_MSG_RESULT([internal])
;;
yes|auto)
network_type="auto"
AC_MSG_RESULT([auto])
;;
no|none)
network_type="disabled"
AC_MSG_RESULT([none])
;;
*)
AC_MSG_ERROR([Unknown network option "$withval"])
;;
esac
],
[
AC_MSG_RESULT([$network_type])
]
)
if test x$network_type = xauto; then
AC_MSG_CHECKING([for automatic network support])
if test "x$have_fork" = "xyes"; then
network_type=exec
elif test "x$win32_specific_codes" = "xenabled"; then
network_type=winhttp
elif test "x$have_network" = "xyes"; then
network_type="internal"
else
network_type="disabled"
fi
AC_MSG_RESULT([$network_type])
fi
# new net123
if test x$network_type != xinternal -a x$network_type != xdisabled; then
AC_DEFINE([NET123], [1], [ Define to for new net123 network stack. ])
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
AC_MSG_ERROR([wininet or winhttp is currently only for Windows])
fi
#### Use Win32 support codes
AM_CONDITIONAL([WIN32_CODES], [ test "x$win32_specific_codes" = xenabled ])
if test x"$network" = xauto; then
if test x"$have_network" = xyes; then
network=enabled
else
network=disabled
fi
fi
if test x"$ipv6" = xauto; then
if test x"$have_ipv6" = xyes; then
AC_MSG_CHECKING([IPv6 use])
if test x"$have_ipv6" = xyes -a x"$network_type" = xinternal; then
ipv6=enabled
else
ipv6=disabled
fi
AC_MSG_RESULT([$ipv6])
fi
if test x$network_type = xinternal -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([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 ])
dnl ############## Terminal choice
AM_CONDITIONAL( [TERM_POSIX], [test "x$term_type" = xposix] )
AM_CONDITIONAL( [TERM_NONE], [test "x$term_type" = xnone] )
AM_CONDITIONAL( [TERM_WIN32], [test "x$term_type" = xwin32] )
dnl ############## FIFO enable
if test x"$fifo" = xauto; then
@@ -2558,7 +2685,7 @@ if test x"$fifo" = xenabled; then
fi
dnl ############## Network enable
if test x"$network" = xenabled; then
if test x"$network_type" = xinternal; 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! ] )
@@ -2601,8 +2728,6 @@ AC_CONFIG_FILES([
AC_OUTPUT
dnl ############## Display Message
echo "
@@ -2613,13 +2738,16 @@ echo "
Compiler Optimization ... $with_optimization
Gapless Support ......... $gapless
Debugging ............... $debugging
Terminal control ........ $term_type
Extreme debugging ....... $xdebugging
Seek table size ......... $seektable
FIFO support ............ $fifo
Buffer .................. $buffer
Network (http streams) .. $network
Network Sockets ......... $network_type
Network (http streams) .. $network_type"
if test x$network_type = xinternal; then
echo " Internal network type ... $network_internal
IPv6 (getaddrinfo) ...... $ipv6"
fi
if test x"$LARGEFILE_BITS" = x; then
echo " File offsets ............ default"
else

View File

@@ -19,6 +19,7 @@ EXTRA_DIST += \
doc/doxyfoot.xhtml \
doc/doxy_examples.c \
doc/doxygen.conf \
doc/windows-notes.html \
doc/examples/mpg123_to_out123.c \
doc/examples/scan.c \
doc/examples/mpglib.c \

View File

@@ -63,7 +63,9 @@ SEQ <bass> <mid> <treble>: simple eq setting...
PITCH <[+|-]value>: adjust playback speed (+0.01 is 1 % faster)
SILENCE: be silent during playback (meaning silence in text form)
SILENCE: be silent during playback (no progress info, opposite of PROGRESS)
PROGRESS: turn on progress display (opposite of SILENCE)
STATE: Print auxiliary state info in several lines (just try it to see what info is there).
@@ -102,7 +104,7 @@ Note: mpg123 returns errors on stderr, so your frontend should
look not only at stdout but also at stderr for responses.
It is a good idea to use --remote-err and just look at stderr.
@R MPG123 (ThOr) v7
@R MPG123 (ThOr) v10
Startup version message. Everything after MPG123 is auxilliary information about behaviour and command support, ID3v2 tag support is new in v3.
@I ID3:<a><b><c>
@@ -175,6 +177,7 @@ to help parsers decide if they got the whole list.
a = 0: playing stopped
a = 1: playing paused
a = 2: playing unpaused
a = 3: end of track reached (followed by another status response)
@E <a>
An error occured

243
doc/windows-notes.html Normal file
View File

@@ -0,0 +1,243 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252"/>
<title></title>
<meta name="generator" content="LibreOffice 7.0.3.1 (Windows)"/>
<meta name="created" content="2021-02-03T20:00:54"/>
<meta name="changed" content="2021-02-13T16:28:26.399000000"/>
<style type="text/css">
@page { size: 8.5in 11in; margin: 0.79in }
p { margin-bottom: 0.1in; direction: ltr; color: #00000a; line-height: 115%; text-align: left; orphans: 2; widows: 2; background: transparent }
p.western { font-family: "Arial", sans-serif; font-size: 12pt; so-language: en-US }
p.cjk { font-family: "NSimSun"; font-size: 12pt; so-language: zh-CN }
p.ctl { font-family: "Arial"; font-size: 12pt; so-language: hi-IN }
a:link { color: #000080; so-language: zxx; text-decoration: underline }
a:visited { color: #800000; so-language: zxx; text-decoration: underline }
</style>
</head>
<body lang="en-US" text="#00000a" link="#000080" vlink="#800000" dir="ltr"><p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<b>GENERAL INFORMATION ON RUNNING MPG123 IN A WINDOWS ENVIR</b><b>O</b><b>NMENT</b></p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<i>(Caution- This is a brief guide, based on my experience running
MPG123 under Windows. This is NOT a sanctioned document from the
MPG123 team. It has not been reviewed by MPG123 for accuracy or
completeness. Use this information at your own risk. DON'T submit
tickets to MPG123 based on anything you read in this document, and
there is NO guarantee as to the validity of information contained
herein. -- J. Amick - 2021-02-13 ) </i>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
A portable (no installation required) MPG123.EXE can be downloaded
from &ldquo;<span style="font-variant: normal"><font color="#330000"><font face="sans, sans-serif"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="font-weight: normal">Win32
and Win64 binaries&rdquo; at </span></span></span></font></font></span>WWW.MPG123.DE<span style="font-variant: normal"><font color="#330000"><font face="sans, sans-serif"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="font-weight: normal">.
</span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font face="Arial, sans-serif"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="font-weight: normal">The
file you want is </span></span></span></font></font></span><font color="#000080"><span lang="zxx"><span style="text-decoration: none">mpg123-v-static-x86-bb.zip</span></span></font><font color="#000080"><span lang="zxx"><span style="font-variant: normal"><font color="#330000"><font face="Arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">,</span></span></span></span></font></font></font></span></span></font><span style="font-variant: normal"><font color="#330000"><font face="Arial, sans-serif"><font size="4" style="font-size: 14pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">
</span></span></span></span></font></font></font></span><span style="font-variant: normal"><font color="#330000"><font face="Arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">where
v (version) is currently &ldquo;1.26.4&rdquo; </span></span></span></span></font></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">and
bb (your system architecture) is either &ldquo;32&rdquo; or &ldquo;64&rdquo;
bit.. Extract the entire downloaded zip. Consider creating a new
target directory named MPG123 in &ldquo;Program Files&rdquo;. Make
sure the target directory is included in your PATH system environment
variable- add if necessary. </span></span></span></span></font></font></span>
</p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">Command
Line usage: </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#444444"><font face="verdana, helvetica, arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><b>mpg123</b></span></span></span></font></font></font></span><span style="font-variant: normal"><font color="#444444"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">
</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#444444"><font face="verdana, helvetica, arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">[
</span></span></span></span></font></font></font></span><span style="font-variant: normal"><font color="#444444"><font face="verdana, helvetica, arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><b>options
</b></span></span></span></font></font></font></span><span style="font-variant: normal"><font color="#444444"><font face="verdana, helvetica, arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">]
</span></span></span></span></font></font></font></span><span style="font-variant: normal"><font color="#444444"><font face="verdana, helvetica, arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><i><span style="text-decoration: none"><span style="font-weight: normal">file</span></span></i></span></font></font></font></span><span style="font-variant: normal"><font color="#444444"><font face="verdana, helvetica, arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">
... </span></span></span></span></font></font></font></span><span style="font-variant: normal"><font color="#444444"><font face="verdana, helvetica, arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><i><span style="text-decoration: none"><span style="font-weight: normal">|
URL </span></span></i></span></font></font></font></span><span style="font-variant: normal"><font color="#444444"><font face="verdana, helvetica, arial, sans-serif"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">...
| -</span></span></span></span></font></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">
</span></span></span></span></font></font></span>
</p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">file
&hellip;</span></span></span></span></font></font></span></p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">Windows
full path file name(s), </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><i><span style="text-decoration: none"><span style="font-weight: normal">surrounded
by double quotes</span></span></i></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">.
The * wildcard is OK. For example: &ldquo;F:\Music\*.mp3&rdquo;.
</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">Surrounding
d</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">ouble
quotes allow file/folder names contain</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">ing</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">
blanks.</span></span></span></span></font></font></span></p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">Option
[-a </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><i><span style="text-decoration: none"><span style="font-weight: normal">dev</span></span></i></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">]
</span></span></span></span></font></font></span>
</p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">Specify
the audio device to use. If not present on the command line, MPG123
will use the Windows default audio device- sharing the same audio
channel with normal Windows sounds. If you want MPG123 to play
through a separate/dedicated audio channel, you have to provide
another audio device (sound card, USB sound device, etc). To see
what sound devices are </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">installed
and </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">available
in your Windows system, access and run the &ldquo;Device Manager&rdquo;
(devmgmt.msc). Click to expand &ldquo;Sound, video and game
controllers&rdquo;. Identify the desired sound device and
double-click or right click to &ldquo;Properties&rdquo;. Select the
&ldquo;Details&rdquo; tab, and look for Property &ldquo;Device
instance path&rdquo; (Win 10) or &ldquo;Device instance id&rdquo;
(Win XP). The &ldquo;Value&rdquo; box will contain one or more
lines- the first line is the one you want- and looks something like
this: USB\VID_0D8C&amp;PID_0014&amp;MI_00\6&amp;175BA917&amp;0&amp;0000.
If you type this line on the command line, surround it with double
quotes. Consider saving this </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">(including
the surrounding double quotes) </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">as
a System environment variable, </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">to</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">
eliminate a lot of future typing if debugging a BAT file: System
Properties &gt; Environment Variables &gt; System Variables.</span></span></span></span></font></font></span></p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">If
you have multiple sound devices in your computer, confirm the Windows
Default Sound Device is set to the one you want for </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">any
audio </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">other
than </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">that
</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">generated
by </span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">MPG123.</span></span></span></span></font></font></span></p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><b>CASE
STUDY- SOUND SOURCE FOR TELEPHONE SYSTEM MUSIC ON HOLD</b></span></span></span></font></font></span></p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">I
needed a music source to implement &ldquo;Music on Hold&rdquo; in our
office phone system. In the past, personal CD/MP3 players have
sufficed, but none would last more than a year playing continuously.
All the inexpensive I-Pod type MP3 players I found couldn&rsquo;t
play and charge at the same time. The solution came in the form of
MPG123 playing a folder of MP3 files on an old XP computer running
unattended in the phone closet, still doing batch file document
backups. A channel of MOH audio exclusively for the phone system was
added in the form of a Sabrent USB-SBCV plug-in audio generator
device capable of continuous</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><i><span style="text-decoration: none"><span style="font-weight: normal">
</span></span></i></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">play
for less than $10 (Amazon). This device requires NO external
drivers- truly plug and play.</span></span></span></span></font></font></span></p>
<p class="western" align="left" style="margin-bottom: 0in; font-variant: normal; letter-spacing: normal; font-style: normal; font-weight: normal; line-height: 100%; text-decoration: none">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">This
application required MPG123 to play a continuous loop of every MP3
file found in a folder named &ldquo;Music On Hold&rdquo;. MPG123 has
the -Z option which does this directly, but files are played in
random order. I preferred to have the files looped in alphabetical
order, which MPG123 will not directly do. A short batch file
(created in the same directory as MPG123.</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">EXE</span></span></span></span></font></font></span><span style="font-variant: normal"><font color="#330000"><font size="3" style="font-size: 12pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="text-decoration: none"><span style="font-weight: normal">)
takes care of this problem. As a template, copy and paste the
following lines into Notepad, and save as a BAT file:</span></span></span></span></font></font></span></p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
@echo off</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
rem Start up an infinite loop</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
for /L %%n in () do (</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
rem Play mp3 files in alphabetical order from specified directory</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
for %%f in (&quot;G:\music on hold\*.mp3&quot;) do (</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
mpg123 -m -a %Sabrent% ^&quot;%%f^&quot; ))</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
This batch file presumes a Sabrent system environment variable set
from the sound device property details as described earlier.
Substitute the correct location of your MP3 files. Remove the -m
option if you want stereo.
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
<br/>
</p>
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
This batch file can be initiated directly from a scheduled task
created to launch when windows starts (or other trigger). Each
version of Windows has its own idiosyncrasies starting a batch file
from a scheduled task, and I recommend a Google search if you have
difficulties. Ditto for having the batch file run in a minimized CMD
window, or no window at all. Consider flushing all console output
(stdout and stderr) when you invoke the batch file from a scheduled
task. For this batch file saved as PLAYEM.BAT- enter &ldquo;PLAYEM &gt;
nul 2&gt;&amp;1&rdquo; on the command line<span style="font-variant: normal"><font color="#242729"><font face="Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, sans-serif"><font size="2" style="font-size: 10pt"><span style="letter-spacing: normal"><span style="font-style: normal"><span style="font-weight: normal">.</span></span></span></font></font></font></span>
</p>
</body>
</html>

View File

@@ -91,7 +91,11 @@ from the respective servers. See also the
.TP
\fB\-u \fIauth\fR, \fB\-\^\-auth \fIauth
HTTP authentication to use when receiving files via HTTP.
The format used is user:password.
The format used is user:password. Mpg123 will clear this quickly, but it may still appear
in sight of other users or even just in your shell history.
.TP
\fB\-\^\-auth-file \fIauthfile
Provide the authentication info via given file instead of command line directly.
.TP
\fB\-\^\-ignore\-mime
Ignore MIME types given by HTTP server. If you know better and want mpg123
@@ -126,7 +130,13 @@ or an URL pointing to a an appropriate list file. Note: only
one
.B \-@
option can be used (if more than one is specified, only the
last one will be recognized).
last one will be recognized). Furthermore, for HTTP resources, the
MIME type information will be used to re-open an actual MPEG stream as
such instead of treating it as playlist file. So you could just always
use
.B \-@
for web resources without bothering if it is a playlist or already the resolved
stream address.
.TP
\fB\-l \fIn\fR, \fB\-\^\-listentry \fIn
Of the playlist, play specified entry only.

View File

@@ -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.29.3
Version: 1.30.0
Release: 1
URL: http://www.mpg123.org/
License: GPL

View File

@@ -1,6 +1,6 @@
function(read_api_version project_version api_version outapi_version synapi_version )
file( READ "${CMAKE_SOURCE_DIR}/../../configure.ac" configure_ac )
file( READ "${CMAKE_CURRENT_SOURCE_DIR}/../../configure.ac" configure_ac )
string( REGEX MATCH "AC_INIT\\(\\[mpg123\\], \\[([0-9\\.]+)" result ${configure_ac} )
set( ${project_version} ${CMAKE_MATCH_1} PARENT_SCOPE )

View File

@@ -8,15 +8,12 @@ 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)
@@ -25,7 +22,6 @@ check_include_file("stdlib.h" HAVE_STDLIB_H)
check_include_file("string.h" HAVE_STRING_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)
@@ -38,7 +34,6 @@ check_include_file("sys/wait.h" HAVE_SYS_WAIT_H)
check_include_file("termios.h" HAVE_TERMIOS)
check_include_file("unistd.h" HAVE_UNISTD_H)
check_include_file("windows.h" HAVE_WINDOWS_H)
function(check_m)
set(CMAKE_REQUIRED_LIBRARIES m)
check_function_exists(sin HAVE_M)
@@ -58,6 +53,9 @@ check_function_exists(shmat HAVE_SHMAT)
check_function_exists(shmdt HAVE_SHMDT)
check_function_exists(shmctl HAVE_SHMCTL)
check_function_exists(strerror HAVE_STRERROR)
check_function_exists(fork HAVE_FORK)
check_function_exists(execvp HAVE_EXECVP)
check_function_exists(ctermid HAVE_CTERMID)
search_libs(gethostbyname GETHOSTBYNAME_LIB nsl socket network)
search_libs(socket SOCKET_LIB socket)
@@ -175,10 +173,6 @@ 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)
@@ -319,7 +313,6 @@ 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)
@@ -376,6 +369,18 @@ if(UNIX)
option(BUILD_PROGRAMS "Build programs" ON)
if(BUILD_PROGRAMS)
if(HAVE_FORK AND HAVE_EXECVP)
set(NET123 ON)
set(NET123_EXEC ON)
endif()
if(HAVE_TERMIOS)
set(TERM_POSIX ON)
else()
set(TERM_NONE ON)
endif()
add_subdirectory("tests")
if(BUILD_LIBOUT123)
@@ -388,12 +393,15 @@ if(UNIX)
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/getlopt.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/httpget.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/resolver.c"
$<$<BOOL:${NET123_EXEC}>:${CMAKE_CURRENT_SOURCE_DIR}/../../../src/net123_exec.c>
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/genre.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/mpg123.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/metaprint.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/local.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/playlist.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/streamdump.c"
$<$<BOOL:${TERM_POSIX}>:${CMAKE_CURRENT_SOURCE_DIR}/../../../src/term_posix.c>
$<$<BOOL:${TERM_NONE}>:${CMAKE_CURRENT_SOURCE_DIR}/../../../src/term_none.c>
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/term.c")
target_link_libraries(${PROJECT_NAME} PRIVATE
compat

View File

@@ -69,8 +69,9 @@
#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
// Define to disable downsampled decoding.
#cmakedefine NO_DOWNSAMPLE 1

View File

@@ -75,6 +75,7 @@ src_mpg123_SOURCES = \
src/streamdump.c \
src/term.c \
src/term.h \
src/terms.h \
src/win32_support.h
# Does that finally work to build/link the correct object file?
@@ -105,10 +106,40 @@ src_mpg123_strip_SOURCES = \
src/getlopt.c \
src/getlopt.h
if TERM_POSIX
src_mpg123_SOURCES += src/term_posix.c
endif
if TERM_WIN32
src_mpg123_SOURCES += src/term_win32.c
endif
if TERM_NONE
src_mpg123_SOURCES += src/term_none.c
endif
if NET123_EXEC
src_mpg123_SOURCES += src/net123.h src/net123_exec.c
endif
if NET123_WINHTTP
src_mpg123_SOURCES += src/net123.h src/net123_winhttp.c
src_mpg123_LDADD += -lwinhttp
endif
if NET123_WININET
src_mpg123_SOURCES += src/net123.h src/net123_wininet.c
src_mpg123_LDADD += -lwininet
endif
if WIN32_CODES
src_mpg123_SOURCES += \
src/win32_support.c \
src/win32_net.c
src/win32_support.c
if NETWORK_WINSOCK
src_mpg123_SOURCES += src/win32_net.c
src_mpg123_LDADD += -lws2_32
endif
src_out123_SOURCES+= \
src/win32_support.c

View File

@@ -1,7 +1,7 @@
/*
common: misc stuff... audio flush, status display...
copyright ?-2020 by the mpg123 project
copyright ?-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
@@ -15,6 +15,8 @@
#include "out123.h"
#include <sys/stat.h>
#include "common.h"
#include "terms.h"
#include "metaprint.h"
#include "debug.h"
@@ -166,6 +168,7 @@ void print_buf(const char* prefix, out123_handle *ao)
void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar
, struct parameter *param)
{
static int old_term_width = -1;
size_t buffered;
off_t decoded;
off_t elapsed;
@@ -183,6 +186,7 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar
char linebuf[256];
char *line = NULL;
#ifndef __OS2__
#ifndef WIN32
#ifndef GENERIC
/* Only generate new stat line when stderr is ready... don't overfill... */
@@ -199,6 +203,7 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar
if(n <= 0) return;
}
#endif
#endif
#endif
if(out123_getformat(ao, &rate, NULL, NULL, &framesize))
return;
@@ -237,6 +242,22 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar
/* 255 is enough for the data I prepare, if there is no terminal width to
fill */
maxlen = term_width(STDERR_FILENO);
if(draw_bar && maxlen > 0 && maxlen < old_term_width)
{
// Hack about draw_bar: That's the normal print_stat that is not followed by
// metadata anyway. No need to double things.
print_stat(fr, offset, ao, 0, param);
if(param->verbose > 2)
fprintf(stderr,"Note: readjusting for smaller terminal (%d to %d)\n", old_term_width, maxlen);
fprintf(stderr, "\n\n\n");
if(param->verbose > 1)
print_header(fr);
else
print_header_compact(fr);
print_id3_tag(fr, param->long_id3, stderr, maxlen);
}
if(draw_bar)
old_term_width = maxlen;
linelen = maxlen > 0 ? maxlen : (sizeof(linebuf)-1);
line = linelen >= sizeof(linebuf)
? malloc(linelen+1) /* Only malloc if it is a really long line. */
@@ -354,7 +375,6 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar
Shouldn't we always fill to maxlen? */
if(maxlen > 0)
memset(line+len, ' ', linelen-len);
#ifdef HAVE_TERMIOS
draw_bar = draw_bar && term_have_fun(STDERR_FILENO,param->term_visual);
/* Use inverse color to draw a progress bar. */
if(maxlen > 0 && draw_bar)
@@ -377,17 +397,9 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar
fprintf(stderr, "%s", line+barlen);
}
else
#endif
fprintf(stderr, "\r%s", line);
}
}
/* Check for changed tags here too? */
if( mpg123_meta_check(fr) & MPG123_NEW_ICY && MPG123_OK == mpg123_icy(fr, &icy) )
{
if(line) /* Clear the inverse video. */
fprintf(stderr, "\r%s", line);
fprintf(stderr, "\nICY-META: %s\n", icy);
}
if(line && line != linebuf)
free(line);
}

View File

@@ -155,6 +155,15 @@ int compat_fclose(FILE *stream)
return fclose(stream);
}
void compat_binmode(int fd, int enable)
{
#if defined(HAVE__SETMODE)
_setmode(fd, enable ? _O_BINARY : _O_TEXT);
#elif defined(HAVE_SETMODE)
setmode(fd, enable ? O_BINARY : O_TEXT);
#endif
}
#ifndef WINDOWS_UWP
/*
@@ -441,7 +450,12 @@ size_t unintr_write(int fd, void const *buffer, size_t bytes)
{
bytes -= part;
written += part;
} else if(errno != EINTR)
} else if(errno != EINTR && errno != EAGAIN
#ifndef __KLIBC__
// OS/2 is funny with POSIX.
&& errno != EWOULDBLOCK
#endif
)
break;
}
return written;
@@ -456,11 +470,16 @@ size_t unintr_read(int fd, void *buffer, size_t bytes)
{
errno = 0;
ssize_t part = read(fd, (char*)buffer+got, bytes);
if(part >= 0)
if(part > 0) // == 0 is end of file
{
bytes -= part;
got += part;
} else if(errno != EINTR)
} else if(errno != EINTR && errno != EAGAIN
#ifndef __KLIBC__
// OS/2 is funny with POSIX.
&& errno != EWOULDBLOCK
#endif
)
break;
}
return got;

View File

@@ -67,6 +67,19 @@
#define ULONG_MAX ((unsigned long)-1)
#endif
#ifndef OFF_MAX
#if SIZEOF_OFF_T == 4
#define OFF_MAX ((uint32_t)-1/2)
#elif SIZEOF_OFF_T == 8
#define OFF_MAX ((uint64_t)-1/2)
#else
#error "Unexpected width of off_t."
#endif
#endif
// Add two values (themselves assumed to be < limit), saturating to given limit.
#define SATURATE_ADD(inout, add, limit) inout = (limit-add >= inout) ? inout+add : limit;
#ifdef HAVE_STRING_H
#include <string.h>
#endif
@@ -74,7 +87,7 @@
#include <strings.h>
#endif
#ifdef OS2
#ifdef __OS2__
#include <float.h>
#endif
@@ -182,9 +195,17 @@ FILE* compat_fdopen(int fd, const char *mode);
int compat_close(int infd);
int compat_fclose(FILE* stream);
/**
* Setting binary mode on a descriptor, where necessary.
* We do not bother with errors. This has to work.
* You can enable or disable binary mode.
*/
void compat_binmode(int fd, int enable);
/* Those do make sense in a separate file, but I chose to include them in compat.c because that's the one source whose object is shared between mpg123 and libmpg123 -- and both need the functionality internally. */
#ifdef WANT_WIN32_UNICODE
#if defined (_WIN32) || defined (__CYGWIN__)
/**
* win32_uni2mbc
* Converts a null terminated UCS-2 string to a multibyte (UTF-8) equivalent.
@@ -198,6 +219,19 @@ int compat_fclose(FILE* stream);
*/
int win32_wide_utf8(const wchar_t * const wptr, char **mbptr, size_t * buflen);
/**
* win32_uni2mbc
* Converts a null terminated UCS-2 string to a multibyte (UTF-7) equivalent.
* Caller is supposed to free allocated buffer.
* @param[in] wptr Pointer to wide string.
* @param[out] mbptr Pointer to multibyte string.
* @param[out] buflen Optional parameter for length of allocated buffer.
* @return status of WideCharToMultiByte conversion.
*
* WideCharToMultiByte - http://msdn.microsoft.com/en-us/library/dd374130(VS.85).aspx
*/
int win32_wide_utf7(const wchar_t * const wptr, char **mbptr, size_t * buflen);
/**
* win32_mbc2uni
* Converts a null terminated UTF-8 string to a UCS-2 equivalent.
@@ -281,11 +315,6 @@ size_t unintr_write(int fd, void const *buffer, size_t bytes);
size_t unintr_read (int fd, void *buffer, size_t bytes);
size_t unintr_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
/* That one comes from Tellie on OS/2, needed in resolver. */
#ifdef __KLIBC__
typedef int socklen_t;
#endif
/* OSX SDK defines an enum with "normal" as value. That clashes with
optimize.h */
#ifdef __APPLE__

View File

@@ -14,7 +14,7 @@
/* Win32 is only supported with unicode now. These headers also cover
module stuff. The WANT_WIN32_UNICODE macro is synonymous with
"want windows-specific API, and only the unicode variants of which". */
#ifdef WANT_WIN32_UNICODE
#if defined (_WIN32) || defined (__CYGWIN__)
#include <wchar.h>
#include <windows.h>
#include <winnls.h>
@@ -63,20 +63,21 @@ char* compat_strdup(const char *src)
}
/* Windows Unicode stuff */
#ifdef WANT_WIN32_UNICODE
int win32_wide_utf8(const wchar_t * const wptr, char **mbptr, size_t * buflen)
/* Provided unconditionally, since WASAPI needs it to configure the audio device */
#if defined (_WIN32) || defined (__CYGWIN__)
static
int win32_wide_common(const wchar_t * const wptr, char **mbptr, size_t * buflen, UINT cp)
{
size_t len;
char *buf;
int ret = 0;
len = WideCharToMultiByte(CP_UTF8, 0, wptr, -1, NULL, 0, NULL, NULL); /* Get utf-8 string length */
len = WideCharToMultiByte(cp, 0, wptr, -1, NULL, 0, NULL, NULL); /* Get utf-8 string length */
buf = calloc(len + 1, sizeof (char)); /* Can we assume sizeof char always = 1? */
if(!buf) len = 0;
else {
if (len != 0) ret = WideCharToMultiByte(CP_UTF8, 0, wptr, -1, buf, len, NULL, NULL); /*Do actual conversion*/
if (len != 0) ret = WideCharToMultiByte(cp, 0, wptr, -1, buf, len, NULL, NULL); /*Do actual conversion*/
buf[len] = '0'; /* Must terminate */
}
*mbptr = buf; /* Set string pointer to allocated buffer */
@@ -84,6 +85,16 @@ int win32_wide_utf8(const wchar_t * const wptr, char **mbptr, size_t * buflen)
return ret;
}
int win32_wide_utf8(const wchar_t * const wptr, char **mbptr, size_t * buflen)
{
return win32_wide_common(wptr, mbptr, buflen, CP_UTF8);
}
int win32_wide_utf7(const wchar_t * const wptr, char **mbptr, size_t * buflen)
{
return win32_wide_common(wptr, mbptr, buflen, CP_UTF7);
}
int win32_utf8_wide(const char *const mbptr, wchar_t **wptr, size_t *buflen)
{
size_t len;

View File

@@ -82,6 +82,9 @@
/* Define to 1 if you have the <CoreServices/CoreServices.h> header file. */
#undef HAVE_CORESERVICES_CORESERVICES_H
/* Define to 1 if you have the `ctermid' function. */
#undef HAVE_CTERMID
/* Define to 1 if you have the <CUlib.h> header file. */
#undef HAVE_CULIB_H
@@ -100,6 +103,12 @@
/* Define to 1 if you have the `dlsym' function. */
#undef HAVE_DLSYM
/* Define to 1 if you have the `execvp' function. */
#undef HAVE_EXECVP
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
@@ -181,6 +190,9 @@
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
/* for Win/DOS system with setmode() */
#undef HAVE_SETMODE
/* Define to 1 if you have the `setpriority' function. */
#undef HAVE_SETPRIORITY
@@ -295,6 +307,9 @@
/* Define to 1 if you have the <ws2tcpip.h> header file. */
#undef HAVE_WS2TCPIP_H
/* for Win/DOS system with _setmode() */
#undef HAVE__SETMODE
/* Define to indicate that float storage follows IEEE754. */
#undef IEEE_FLOAT
@@ -320,6 +335,9 @@
/* Define to the shared archive member specification, say "(shr.o)". */
#undef LT_SHARED_LIB_MEMBER
/* Define to for new net123 network stack. */
#undef NET123
/* Define if network support is enabled. */
#undef NETWORK

View File

@@ -319,8 +319,8 @@ static void generic_load(mpg123_handle *fr, char *arg, int state)
}
else generic_sendinfo(arg);
if(htd.icy_name.fill) generic_sendstr(1, "I ICY-NAME: %s", htd.icy_name.p);
if(htd.icy_url.fill) generic_sendstr(1, "I ICY-URL: %s", htd.icy_url.p);
if(filept->htd.icy_name.fill) generic_sendstr(1, "I ICY-NAME: %s", filept->htd.icy_name.p);
if(filept->htd.icy_url.fill) generic_sendstr(1, "I ICY-URL: %s", filept->htd.icy_url.p);
mode = state;
init = 1;
@@ -408,7 +408,7 @@ int control_generic (mpg123_handle *fr)
#endif
/* the command behaviour is different, so is the ID */
/* now also with version for command availability */
fprintf(outstream, "@R MPG123 (ThOr) v9\n");
fprintf(outstream, "@R MPG123 (ThOr) v10\n");
#ifdef FIFO
if(param.fifo)
{
@@ -451,6 +451,7 @@ int control_generic (mpg123_handle *fr)
if (n == 0) {
if (!play_frame())
{
generic_sendmsg("P 3");
out123_pause(ao);
/* When the track ended, user may want to keep it open (to seek back),
so there is a decision between stopping and pausing at the end. */
@@ -598,6 +599,13 @@ int control_generic (mpg123_handle *fr)
continue;
}
/* PROGRESS, opposite of silence */
if(!strcasecmp(comstr, "PROGRESS")) {
silent = 0;
generic_sendmsg("progress");
continue;
}
if(!strcasecmp(comstr, "MUTE")) {
set_mute(ao, muted=TRUE);
generic_sendmsg("mute");
@@ -703,7 +711,8 @@ int control_generic (mpg123_handle *fr)
generic_sendmsg("H FORMAT: print out sampling rate in Hz and channel count");
generic_sendmsg("H SEQ <bass> <mid> <treble>: simple eq setting...");
generic_sendmsg("H PITCH <[+|-]value>: adjust playback speed (+0.01 is 1 %% faster)");
generic_sendmsg("H SILENCE: be silent during playback (meaning silence in text form)");
generic_sendmsg("H SILENCE: be silent during playback (no progress info, opposite of PROGRESS)");
generic_sendmsg("H PROGRESS: turn on progress display (opposite of SILENCE)");
generic_sendmsg("H STATE: Print auxiliary state info in several lines (just try it to see what info is there).");
generic_sendmsg("H TAG/T: Print all available (ID3) tag info, for ID3v2 that gives output of all collected text fields, using the ID3v2.3/4 4-character names. NOTE: ID3v2 data will be deleted on non-forward seeks.");
generic_sendmsg("H The output is multiple lines, begin marked by \"@T {\", end by \"@T }\".");
@@ -740,13 +749,9 @@ int control_generic (mpg123_handle *fr)
int cn;
if(sscanf(arg, "%lf %lf %lf", &b, &m, &t) == 3)
{
/* Consider adding mpg123_seq()... but also, on could define a nicer courve for that. */
for(cn=0; cn < 1; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, b);
for(cn=1; cn < 2; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, m);
for(cn=2; cn < 32; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, t);
mpg123_eq_bands(fr, MPG123_LR, 0, 0, b);
mpg123_eq_bands(fr, MPG123_LR, 1, 1, m);
mpg123_eq_bands(fr, MPG123_LR, 2, 31, t);
generic_sendmsg("bass: %f mid: %f treble: %f", b, m, t);
}
else generic_sendmsg("E invalid arguments for SEQ: %s", arg);

View File

@@ -93,6 +93,25 @@ static const char* mime_pls[] =
};
static const char** mimes[] = { mime_file, mime_m3u, mime_pls, NULL };
int append_accept(mpg123_string *s)
{
size_t i,j;
if(!mpg123_add_string(s, "Accept: ")) return FALSE;
/* We prefer what we know. */
for(i=0; mimes[i] != NULL; ++i)
for(j=0; mimes[i][j] != NULL; ++j)
{
if( !mpg123_add_string(s, mimes[i][j])
|| !mpg123_add_string(s, ", ") )
return FALSE;
}
/* Well... in the end, we accept everything, trying to make sense with reality. */
if(!mpg123_add_string(s, "*/*")) return FALSE;
return TRUE;
}
int debunk_mime(const char* mime)
{
int i,j;
@@ -268,8 +287,6 @@ void get_header_string(mpg123_string *response, const char *fieldname, mpg123_st
/* shoutcsast meta data: 1=on, 0=off */
char *httpauth = NULL;
size_t accept_length(void)
{
int i,j;
@@ -320,26 +337,6 @@ int proxy_init(struct httpdata *hd)
return ret;
}
static int append_accept(mpg123_string *s)
{
size_t i,j;
if(!mpg123_add_string(s, "Accept: ")) return FALSE;
/* We prefer what we know. */
for(i=0; mimes[i] != NULL; ++i)
for(j=0; mimes[i][j] != NULL; ++j)
{
if( !mpg123_add_string(s, mimes[i][j])
|| !mpg123_add_string(s, ", ") )
return FALSE;
}
/* Well... in the end, we accept everything, trying to make sense with reality. */
if(!mpg123_add_string(s, "*/*\r\n")) return FALSE;
return TRUE;
}
/*
Converts spaces to "%20" ... actually, I have to ask myself why.
What about converting them to "+" instead? Would make things a lot easier.
@@ -421,13 +418,15 @@ int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *por
}
/* Acceptance, stream setup. */
if( !append_accept(request)
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, icy)
|| !mpg123_add_string(request, "\r\n") )
return FALSE;
/* Authorization. */
if (httpauth1->fill || httpauth) {
if (httpauth1->fill || param.httpauth) {
char *buf;
if(!mpg123_add_string(request,"Authorization: Basic ")) return FALSE;
if(httpauth1->fill) {
@@ -441,15 +440,15 @@ int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *por
}
encode64(httpauth1->p,buf);
} else {
if(strlen(httpauth) > SIZE_MAX / 4 - 4 ) return FALSE;
if(strlen(param.httpauth) > SIZE_MAX / 4 - 4 ) return FALSE;
buf=(char *)malloc((strlen(httpauth) + 1) * 4);
buf=(char *)malloc((strlen(param.httpauth) + 1) * 4);
if(!buf)
{
error("malloc() for http auth failed, out of memory.");
return FALSE;
}
encode64(httpauth,buf);
encode64(param.httpauth,buf);
}
if( !mpg123_add_string(request, buf) || !mpg123_add_string(request, "\r\n"))
@@ -502,7 +501,7 @@ static int resolve_redirect(mpg123_string *response, mpg123_string *request_url,
return TRUE;
}
int http_open(char* url, struct httpdata *hd)
int http_open(const char* url, struct httpdata *hd)
{
mpg123_string purl, host, port, path;
mpg123_string request, response, request_url;
@@ -719,7 +718,7 @@ exit: /* The end as well as the exception handling point... */
#else /* NETWORK */
/* stub */
int http_open (char* url, struct httpdata *hd)
int http_open (const char* url, struct httpdata *hd)
{
if(!param.quiet)
error("HTTP support not built in.");

View File

@@ -14,6 +14,8 @@
#define _HTTPGET_H_
#include "mpg123.h"
#include "net123.h"
/* Pulled in by mpg123app.h! */
struct httpdata
@@ -54,13 +56,13 @@ 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\r\n"
#define icy_no "Icy-MetaData: 0\r\n"
#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);
extern char *proxyurl;
extern unsigned long proxyip;
/* takes url and content type string address, opens resource, returns fd for data, allocates and sets content type */
extern int http_open (char* url, struct httpdata *hd);
extern char *httpauth;
extern int http_open (const char* url, struct httpdata *hd);
#endif

View File

@@ -17,6 +17,7 @@
#define compat_close INT123_compat_close
#define compat_fclose INT123_compat_fclose
#define win32_wide_utf8 INT123_win32_wide_utf8
#define win32_wide_utf7 INT123_win32_wide_utf7
#define win32_utf8_wide INT123_win32_utf8_wide
#define compat_catpath INT123_compat_catpath
#define compat_isdir INT123_compat_isdir

View File

@@ -984,6 +984,12 @@ int attribute_align_arg mpg123_volume_change(mpg123_handle *mh, double change)
return mpg123_volume(mh, change + (double) mh->p.outscale);
}
int attribute_align_arg mpg123_volume_change_db(mpg123_handle *mh, double change)
{
if(mh == NULL) return MPG123_ERR;
return mpg123_volume(mh, dbchange(mh->p.outscale, change));
}
int attribute_align_arg mpg123_volume(mpg123_handle *mh, double vol)
{
if(mh == NULL) return MPG123_ERR;

View File

@@ -454,8 +454,8 @@ int attribute_align_arg mpg123_getstate2(mpg123_handle *mh, int key, long *val,
int attribute_align_arg mpg123_eq(mpg123_handle *mh, enum mpg123_channels channel, int band, double val)
{
#ifndef NO_EQUALIZER
if(mh == NULL) return MPG123_BAD_HANDLE;
#ifndef NO_EQUALIZER
if(band < 0 || band > 31){ mh->err = MPG123_BAD_BAND; return MPG123_ERR; }
switch(channel)
{
@@ -478,9 +478,42 @@ int attribute_align_arg mpg123_eq2(mpg123_handle *mh, int channel, int band, dou
return mpg123_eq(mh, channel, band, val);
}
int attribute_align_arg mpg123_eq_bands(mpg123_handle *mh, int channel, int a, int b, double factor)
{
if(mh == NULL) return MPG123_BAD_HANDLE;
#ifndef NO_EQUALIZER
int ret;
// Always count up.
if(a>b){ int s=a; a=b; b=s; }
for(int n=a; n<=b; ++n)
if( (ret=mpg123_eq(mh, channel, n, factor)) != MPG123_OK )
return ret;
#endif
return MPG123_OK;
}
int attribute_align_arg mpg123_eq_change(mpg123_handle *mh, int channel, int a, int b, double db)
{
if(mh == NULL) return MPG123_BAD_HANDLE;
#ifndef NO_EQUALIZER
// Always count up.
if(a>b){ int s=a; a=b; b=s; }
for(int band=a; band<=b; ++band)
{
if(band < 0 || band > 31){ mh->err = MPG123_BAD_BAND; return MPG123_ERR; }
if(channel & MPG123_LEFT)
mh->equalizer[0][band] = DOUBLE_TO_REAL(dbchange(REAL_TO_DOUBLE(mh->equalizer[0][band]), db));
if(channel & MPG123_RIGHT)
mh->equalizer[1][band] = DOUBLE_TO_REAL(dbchange(REAL_TO_DOUBLE(mh->equalizer[1][band]), db));;
mh->have_eq_settings = TRUE;
}
#endif
return MPG123_OK;
}
double attribute_align_arg mpg123_geteq(mpg123_handle *mh, enum mpg123_channels channel, int band)
{
double ret = 0.;
double ret = 1.;
#ifndef NO_EQUALIZER
/* Handle this gracefully. When there is no band, it has no volume. */

View File

@@ -1093,6 +1093,28 @@ MPG123_EXPORT int mpg123_eq( mpg123_handle *mh
MPG123_EXPORT int mpg123_eq2( mpg123_handle *mh
, int channel, int band, double val );
/** Set a range of equalizer bands
* \param channel Can be #MPG123_LEFT, #MPG123_RIGHT or
* #MPG123_LEFT|#MPG123_RIGHT for both.
* \param a The first equalizer band to set (from 0 to 31)
* \param b The last equalizer band to set (from 0 to 31)
* \param factor The (linear) adjustment factor, 1 being neutral.
* \return MPG123_OK on success
*/
MPG123_EXPORT int mpg123_eq_bands( mpg123_handle *mh
, int channel, int a, int b, double factor );
/** Change a range of equalizer bands
* \param channel Can be #MPG123_LEFT, #MPG123_RIGHT or
* #MPG123_LEFT|#MPG123_RIGHT for both.
* \param a The first equalizer band to change (from 0 to 31)
* \param b The last equalizer band to change (from 0 to 31)
* \param db The adjustment in dB (limited to +/- 60 dB).
* \return MPG123_OK on success
*/
MPG123_EXPORT int mpg123_eq_change( mpg123_handle *mh
, int channel, int a, int b, double db );
#ifdef MPG123_ENUM_API
/** Get the 32 Band Audio Equalizer settings.
*
@@ -1141,6 +1163,13 @@ MPG123_EXPORT int mpg123_volume(mpg123_handle *mh, double vol);
*/
MPG123_EXPORT int mpg123_volume_change(mpg123_handle *mh, double change);
/** Adjust output volume including the RVA setting by chosen amount
* \param mh handle
* \param change volume adjustment in decibels (limited to +/- 60 dB)
* \return MPG123_OK on success
*/
MPG123_EXPORT int mpg123_volume_change_db(mpg123_handle *mh, double db);
/** Return current volume setting, the actual value due to RVA, and the RVA
* adjustment itself. It's all as double float value to abstract the sample
* format. The volume values are linear factors / amplitudes (not percent)
@@ -1741,7 +1770,7 @@ MPG123_EXPORT int mpg123_id3( mpg123_handle *mh
, mpg123_id3v1 **v1, mpg123_id3v2 **v2 );
/** Return pointers to and size of stored raw ID3 data if storage has
* been configured with MPG123_RAW_ID3 and stream parsing passed the
* been configured with MPG123_STORE_RAW_ID3 and stream parsing passed the
* metadata already. Null value with zero size is a possibility!
* The storage can change at any next API call.
*

View File

@@ -339,4 +339,16 @@ int open_fixed_post(mpg123_handle *mh, int channels, int encoding);
#define TIMEOUT_READ
#endif
// Change a given linear factor by the given dB value, bounded
// to +/- 60 dB.
static inline double dbchange(double base_factor, double db)
{
double nscale = base_factor * pow(10, db/20);
if(nscale < 0.001) // -60 dB
nscale = 0.001;
if(nscale > 1000)
nscale = 1000; // +60 dB
return nscale;
}
#endif

View File

@@ -129,7 +129,8 @@ static ssize_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ssize_t count
return READER_ERROR;
}
if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
if(!(fr->rdat.flags & READER_BUFFERED))
SATURATE_ADD(fr->rdat.filepos, ret, OFF_MAX);
cnt += ret;
fr->icy.next -= ret;
if(fr->icy.next > 0)
@@ -147,7 +148,8 @@ static ssize_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ssize_t count
if(ret == 0) break;
debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos );
if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; /* 1... */
if(!(fr->rdat.flags & READER_BUFFERED))
SATURATE_ADD(fr->rdat.filepos, ret, OFF_MAX); /* 1... */
if((meta_size = ((size_t) temp_buff) * 16))
{
@@ -166,7 +168,8 @@ static ssize_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ssize_t count
left -= ret;
}
meta_buff[meta_size] = 0; /* string paranoia */
if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
if(!(fr->rdat.flags & READER_BUFFERED))
SATURATE_ADD(fr->rdat.filepos, ret, OFF_MAX);
if(fr->icy.data) free(fr->icy.data);
fr->icy.data = meta_buff;
@@ -218,7 +221,8 @@ static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t coun
ret = fr->rdat.fdread(fr,buf+cnt,count-cnt);
if(ret < 0) return READER_ERROR;
if(ret == 0) break;
if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
if(!(fr->rdat.flags & READER_BUFFERED))
SATURATE_ADD(fr->rdat.filepos, ret, OFF_MAX);
cnt += ret;
}
return cnt;
@@ -396,7 +400,10 @@ static off_t generic_tell(mpg123_handle *fr)
{
#ifndef NO_FEEDER
if(fr->rdat.flags & READER_BUFFERED)
fr->rdat.filepos = fr->rdat.buffer.fileoff+fr->rdat.buffer.pos;
{
fr->rdat.filepos = fr->rdat.buffer.fileoff;
SATURATE_ADD(fr->rdat.filepos, fr->rdat.buffer.pos, OFF_MAX);
}
#endif
return fr->rdat.filepos;
@@ -458,6 +465,7 @@ static off_t get_fileinfo(mpg123_handle *fr)
debug("cannot seek back");
return -1;
}
fr->rdat.filepos = 0; // un-do our seeking here
debug1("returning length: %"OFF_P, (off_p)len);
return len;
@@ -816,7 +824,8 @@ static int feed_seek_frame(mpg123_handle *fr, off_t num){ return READER_ERROR; }
static void buffered_forget(mpg123_handle *fr)
{
bc_forget(&fr->rdat.buffer);
fr->rdat.filepos = fr->rdat.buffer.fileoff + fr->rdat.buffer.pos;
fr->rdat.filepos = fr->rdat.buffer.fileoff;
SATURATE_ADD(fr->rdat.filepos, fr->rdat.buffer.pos, OFF_MAX);
}
off_t feed_set_pos(mpg123_handle *fr, off_t pos)
@@ -1064,8 +1073,8 @@ static int default_init(mpg123_handle *fr)
if(fr->p.icy_interval > 0) fr->rdat.lseek = nix_lseek;
#endif
fr->rdat.filelen = fr->p.flags & MPG123_NO_PEEK_END ? -1 : get_fileinfo(fr);
fr->rdat.filepos = 0;
fr->rdat.filelen = fr->p.flags & MPG123_NO_PEEK_END ? -1 : get_fileinfo(fr);
if(fr->p.flags & MPG123_FORCE_SEEKABLE)
fr->rdat.flags |= READER_SEEKABLE;
/*

View File

@@ -724,6 +724,8 @@ out123_play(out123_handle *ao, void *bytes, size_t count)
, ao->flags & OUT123_KEEP_PLAYING );
if(written > 0)
{
if(written > block)
written = block; // Safeguard against sloppy output modules.
bytes = (char*)bytes+written;
sum += written;
count -= written;

View File

@@ -22,17 +22,20 @@
#include "debug.h"
// Only one instance at a time! This all needs to go into userptr!
static BOOL opened = FALSE;
/* complementary audio parameters */
int numbuffers = 5; /* total audio buffers, _bare_ minimum = 4 (cuz of prio boost check) */
int audiobufsize = 4884;
int lockdevice = FALSE;
USHORT volume = 100;
char *boostprio = NULL;
char *normalprio = NULL;
unsigned char boostclass = 3, normalclass = 2;
signed char boostdelta = 0, normaldelta = 31;
unsigned char mmerror[160] = {0};
int playingframe;
static int numbuffers = 8; /* total audio buffers, _bare_ minimum = 4 (cuz of prio boost check) */
#define audiobufsize 4096
static int lockdevice = FALSE;
static USHORT volume = 100;
static char *boostprio = NULL;
static char *normalprio = NULL;
static unsigned char boostclass = 3, normalclass = 2;
static signed char boostdelta = 0, normaldelta = 31;
static unsigned char mmerror[160] = {0};
static int playingframe;
/* audio buffers */
static ULONG ulMCIBuffers;
@@ -45,13 +48,24 @@ static MCI_SET_PARMS msp = {0};
static MCI_STATUS_PARMS mstatp = {0};
static MCI_MIX_BUFFER *MixBuffers = NULL;
struct prebuf
{
unsigned char d[audiobufsize]; // data area
int fill; // number of bytes in there
};
// Being lazy for draining.
static unsigned char zbuf[audiobufsize] = {0};
typedef struct
{
MCI_MIX_BUFFER *NextBuffer;
int frameNum;
} BUFFERINFO;
BUFFERINFO *bufferinfo = NULL;
// This static business is EVIL!
// All this needs to go into userptr to allow multiple instances.
static BUFFERINFO *bufferinfo = NULL;
static HEV dataplayed = 0;
@@ -65,7 +79,7 @@ static BOOL nomoredata,nobuffermode,justflushed;
static TIB *mainthread; /* thread info to set thread priority */
ULONG keyboardtid;
static ULONG keyboardtid;
static LONG APIENTRY DARTEvent(ULONG ulStatus, MCI_MIX_BUFFER *PlayedBuffer, ULONG ulFlags)
@@ -158,12 +172,16 @@ static int set_volume(out123_handle *ao, USHORT setvolume)
int open_os2(out123_handle *ao)
{
if(opened)
return -1;
ULONG rc,i;
char *temp;
ULONG openflags;
PPIB ppib;
USHORT bits;
const char *dev = ao->device;
struct prebuf *pb = NULL;
if(maop.usDeviceID) return (maop.usDeviceID);
@@ -180,7 +198,13 @@ int open_os2(out123_handle *ao)
else if(ao->format == MPG123_ENC_UNSIGNED_8)
bits = 8;
else return -1;
ao->userptr = malloc(sizeof(struct prebuf));
if(!ao->userptr)
return -1;
pb = (struct prebuf*)ao->userptr;
pb->fill = 0;
/* open the mixer device */
memset (&maop, 0, sizeof(maop));
maop.usDeviceID = 0;
@@ -324,54 +348,88 @@ int open_os2(out123_handle *ao)
rc = mmp.pmixWrite( mmp.ulMixHandle,
MixBuffers,
ulMCIBuffers );
opened = TRUE;
return maop.usDeviceID;
}
// Always write full blocks of audiobufsize. The engine does not like
// things otherwise. Using a local prebuffer for the leftovers.
static int write_os2(out123_handle *ao,unsigned char *buf,int len)
{
/* if we're too quick, let's wait */
if(nobuffermode)
int written = 0;
struct prebuf *pb = ao->userptr;
mdebug("write_os2(%p, %p, %d)", ao, buf, len);
while(len > 0)
{
MCI_MIX_BUFFER *temp = playingbuffer;
while(
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) &&
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) &&
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) )
if(len + pb->fill < audiobufsize)
{
DosResetEventSem(dataplayed,&resetcount);
DosWaitEventSem(dataplayed, -1);
temp = playingbuffer;
mdebug("storing into pb %p @ %p, %d on top of %d", pb->d, pb->d+pb->fill, len, pb->fill);
// just collect until we got a full buffer
memcpy(pb->d + pb->fill, buf, len);
pb->fill += len;
written += len;
break;
}
} else {
while(tobefilled == playingbuffer)
// Now, we at least got one full buffer to serve.
/* if we're too quick, let's wait */
if(nobuffermode)
{
DosResetEventSem(dataplayed,&resetcount);
DosWaitEventSem(dataplayed, -1);
MCI_MIX_BUFFER *temp = playingbuffer;
while(
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) &&
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) &&
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) )
{
DosResetEventSem(dataplayed,&resetcount);
DosWaitEventSem(dataplayed, -1);
temp = playingbuffer;
}
} else {
while(tobefilled == playingbuffer)
{
DosResetEventSem(dataplayed,&resetcount);
DosWaitEventSem(dataplayed, -1);
}
}
if (justflushed) {
justflushed = FALSE;
} else {
nomoredata = FALSE;
int got = 0;
// First the rest from the prebuffer, then the remaining part from the new stuff.
if(pb->fill)
{
mdebug("copy all %d bytes of prebuffer from %p to %p", pb->fill, pb->d, tobefilled->pBuffer);
memcpy(tobefilled->pBuffer, pb->d, pb->fill);
got = pb->fill;
pb->fill = 0;
}
int therest = audiobufsize - got;
// len + got >= audiobufsize!!
mdebug("copy therest %d from %p to %p", therest, buf, ((unsigned char*)tobefilled->pBuffer)+got);
memcpy(((unsigned char*)tobefilled->pBuffer)+got, buf, therest);
debug("done with buffer writes");
buf += therest;
len -= therest;
written += therest;
tobefilled->ulBufferLength = got+therest; // always == audiobufsize!
// ((BUFFERINFO *) tobefilled->ulUserParm)->frameNum = fr->frameNum;
/* if we're out of the water (3rd ahead buffer filled),
let's reduce our priority */
if(tobefilled == ( (BUFFERINFO *) ( (BUFFERINFO *) ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer)
DosSetPriority(PRTYS_THREAD,normalclass,normaldelta,mainthread->tib_ptib2->tib2_ultid);
tobefilled = ((BUFFERINFO *) tobefilled->ulUserParm)->NextBuffer;
}
}
if (justflushed) {
justflushed = FALSE;
} else {
nomoredata = FALSE;
memcpy(tobefilled->pBuffer, buf, len);
tobefilled->ulBufferLength = len;
// ((BUFFERINFO *) tobefilled->ulUserParm)->frameNum = fr->frameNum;
/* if we're out of the water (3rd ahead buffer filled),
let's reduce our priority */
if(tobefilled == ( (BUFFERINFO *) ( (BUFFERINFO *) ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer)
DosSetPriority(PRTYS_THREAD,normalclass,normaldelta,mainthread->tib_ptib2->tib2_ultid);
tobefilled = ((BUFFERINFO *) tobefilled->ulUserParm)->NextBuffer;
}
return len;
return written;
}
#if 0
@@ -457,6 +515,12 @@ int audio_trash_buffers(out123_handle *ao)
static int close_os2(out123_handle *ao)
{
opened = FALSE;
if(ao && ao->userptr)
{
free(ao->userptr);
ao->userptr = NULL;
}
ULONG rc;
if(!maop.usDeviceID)
@@ -626,9 +690,26 @@ static int get_devices_os2(char *info, int deviceid)
}
}
// at least drain out our prebuffer, proper draining
// should be (re?)enabled, too
static void drain_os2(out123_handle *ao)
{
if(!ao)
return;
ao->write(ao, zbuf, audiobufsize);
if(ao->userptr)
((struct prebuf*)ao->userptr)->fill = 0;
while(!nomoredata)
{
DosResetEventSem(dataplayed,&resetcount);
DosWaitEventSem(dataplayed, -1);
}
}
static void flush_os2(out123_handle *ao)
{
if(ao && ao->userptr)
((struct prebuf*)ao->userptr)->fill = 0;
}
@@ -642,7 +723,8 @@ static int init_os2(out123_handle* ao)
ao->write = write_os2;
ao->get_formats = get_formats_os2;
ao->close = close_os2;
ao->drain = drain_os2;
/* Success */
return 0;
}

View File

@@ -89,7 +89,7 @@ static int check_for_server()
static int open_pulse(out123_handle *ao)
{
int err;
int err = 0;
pa_simple* pas = NULL;
pa_sample_spec ss;
/* Check if already open ? */
@@ -225,7 +225,7 @@ static int close_pulse(out123_handle *ao)
pa_simple *pas = (pa_simple*)ao->userptr;
if (pas) {
int err; /* Do we really want to handle errors here? End is the end. */
int err = 0; /* Do we really want to handle errors here? End is the end. */
pa_simple_drain(pas, &err);
pa_simple_free(pas);
ao->userptr = NULL;
@@ -239,7 +239,7 @@ static void flush_pulse(out123_handle *ao)
pa_simple *pas = (pa_simple*)ao->userptr;
if (pas) {
int err;
int err = 0;
pa_simple_flush( pas, &err );
if(err && !AOQUIET)
error1("Failed to flush audio: %s", pa_strerror(err));

View File

@@ -6,7 +6,13 @@
based on win32.c
*/
#define _WIN32_WINNT 0x601
#if defined(_WIN32_WINNT)
# if _WIN32_WINNT < 0x0601
# error "wrong _WIN32_WINNT value"
# endif
#else
# define _WIN32_WINNT 0x0601
#endif
#define COBJMACROS 1
#include "out123_int.h"
#include <inttypes.h>

View File

@@ -170,9 +170,7 @@ static int open_file(struct wavdata *wdat, char *filename)
if(!filename || !strcmp("-",filename) || !strcmp("", filename))
{
wdat->wavfp = stdout;
#ifdef WIN32
_setmode(STDOUT_FILENO, _O_BINARY);
#endif
compat_binmode(STDOUT_FILENO, TRUE);
/* If stdout is redirected to a file, seeks suddenly can work.
Doing one here to ensure that such a file has the same output
it had when opening directly as such. */

View File

@@ -24,17 +24,6 @@
#endif
#include "compat.h"
#ifdef __EMX__
/* Special ways for OS/2 EMX */
#include <stdlib.h>
#else
/* POSIX stuff */
#ifdef HAVE_TERMIOS
#include <termios.h>
#include <sys/ioctl.h>
#endif
#endif
#include "local.h"
#ifdef HAVE_WCHAR_H
@@ -118,76 +107,6 @@ static int is_utf8(const char *lang)
return 0;
}
int term_have_fun(int fd, int want_visuals)
{
if(term_is_fun > -1)
return term_is_fun;
else
term_is_fun = 0;
#ifdef HAVE_TERMIOS
if(term_width(fd) > 0 && want_visuals)
{
/* Only play with non-dumb terminals. */
char *tname = compat_getenv("TERM");
if(tname)
{
if(strcmp(tname, "") && strcmp(tname, "dumb"))
term_is_fun = 1;
free(tname);
}
}
#endif
return term_is_fun;
}
/* Also serves as a way to detect if we have an interactive terminal. */
int term_width(int fd)
{
#ifdef __EMX__
/* OS/2 */
int s[2];
_scrsize (s);
if (s[0] >= 0)
return s[0];
#else
#ifdef HAVE_TERMIOS
/* POSIX */
struct winsize geometry;
geometry.ws_col = 0;
if(ioctl(fd, TIOCGWINSZ, &geometry) >= 0)
return (int)geometry.ws_col;
#else
#ifdef WIN32
CONSOLE_SCREEN_BUFFER_INFO pinfo;
HANDLE hStdout;
DWORD handle;
switch(fd){
case STDIN_FILENO:
handle = STD_INPUT_HANDLE;
break;
case STDOUT_FILENO:
handle = STD_OUTPUT_HANDLE;
break;
case STDERR_FILENO:
handle = STD_ERROR_HANDLE;
break;
default:
return -1;
}
hStdout = GetStdHandle(handle);
if(hStdout == INVALID_HANDLE_VALUE || hStdout == NULL)
return -1;
if(GetConsoleScreenBufferInfo(hStdout, &pinfo)){
return pinfo.dwMaximumWindowSize.X;
}
#endif
#endif
#endif
return -1;
}
// Moved encoding stuff over from metaprint.c and removed references to libmpg123,
// meaning no mpg123_string for you!

View File

@@ -358,7 +358,7 @@ void print_id3_tag(mpg123_handle *mh, int long_id3, FILE *out, int linelimit)
memcpy(lang, &v2->text[i].lang, 3);
lang[3] = 0;
printf("Lyrics begin, language: %s; %s\n\n", lang, v2->text[i].description.fill ? v2->text[i].description.p : "");
fprintf(out, "Lyrics begin, language: %s; %s\n\n", lang, v2->text[i].description.fill ? v2->text[i].description.p : "");
mpg123_init_string(&innline);
mpg123_init_string(&outline);
@@ -369,7 +369,7 @@ void print_id3_tag(mpg123_handle *mh, int long_id3, FILE *out, int linelimit)
/* Either found end of a line or end of the string (null byte) */
mpg123_set_substring(&innline, uslt->p, a, b-a);
mpg_utf8outstr(&outline, &innline, is_term);
printf(" %s\n", outline.p);
fprintf(out, " %s\n", outline.p);
if(uslt->p[b] == uslt->fill) break; /* nothing more */
@@ -381,10 +381,12 @@ void print_id3_tag(mpg123_handle *mh, int long_id3, FILE *out, int linelimit)
mpg123_free_string(&innline);
mpg123_free_string(&outline);
printf("\nLyrics end.\n");
fprintf(out, "\nLyrics end.\n");
}
}
}
// A separator line just looks nicer.
fprintf(out, "\n");
}
void print_icy(mpg123_handle *mh, FILE *outstream)

View File

@@ -133,6 +133,8 @@ int do_work(mpg123_handle *m)
{
int ret;
size_t count = 0;
compat_binmode(STDIN_FILENO, TRUE);
compat_binmode(STDOUT_FILENO, TRUE);
ret = mpg123_open_fd(m, STDIN_FILENO);
if(ret != MPG123_OK) return ret;

View File

@@ -36,8 +36,8 @@
#include "sysutil.h"
#include "getlopt.h"
#include "term.h"
#include "terms.h"
#include "playlist.h"
#include "httpget.h"
#include "metaprint.h"
#include "httpget.h"
#include "streamdump.h"
@@ -63,12 +63,10 @@ struct parameter param = {
DEFAULT_OUTPUT_MODULE, /* output module */
NULL, /* output device */
0, /* destination (headphones, ...) */
#ifdef HAVE_TERMIOS
FALSE, /* term control */
TRUE, /* term visuals */
MPG123_TERM_USR1,
MPG123_TERM_USR2,
#endif
FALSE , /* checkrange */
0 , /* force_reopen, always (re)opens audio device for next song */
FALSE, /* try to run process in 'realtime mode' */
@@ -118,6 +116,12 @@ struct parameter param = {
,0 /* ICY interval */
,"mpg123" /* name */
,0. /* device buffer */
#if defined(NETWORK) || defined(NET123)
,NULL /* auth */
#endif
#ifdef NET123
,"auto" /* network_backend */
#endif
};
mpg123_handle *mh = NULL;
@@ -129,7 +133,6 @@ static long output_propflags = 0;
char *prgName = NULL;
/* ThOr: pointers are not TRUE or FALSE */
char *equalfile = NULL;
struct httpdata htd;
int fresh = TRUE;
FILE* aux_out = NULL; /* Output for interesting information, normally on stdout to be parseable. */
@@ -144,6 +147,7 @@ enum runmodes
static int runmode = RUN_MAIN;
int stdin_is_term = FALSE; // It's an interactive terminal.
int stdout_is_term = FALSE; // It's an interactive terminal.
int stderr_is_term = FALSE; // It's an interactive terminal.
int got_played = 0; // State of attempted playback and success: 0, -1, 1
@@ -151,9 +155,7 @@ int intflag = FALSE;
int deathflag = FALSE;
static int skip_tracks = 0;
static int filept = -1;
static int network_sockets_used = 0; /* Win32 socket open/close Support */
struct stream *filept = NULL;
char *fullprogname = NULL; /* Copy of argv[0]. */
char *binpath; /* Path to myself. */
@@ -275,10 +277,8 @@ static void controlled_drain(void)
out123_ndrain(ao, drain_block);
if(param.verbose)
print_buf("Draining buffer: ", ao);
#ifdef HAVE_TERMIOS
if(param.term_ctrl)
term_control(mh, ao);
#endif
}
while(!intflag && out123_buffered(ao));
if(param.verbose)
@@ -305,7 +305,8 @@ void safe_exit(int code)
if(cleanup_mpg123) mpg123_exit();
httpdata_free(&htd);
stream_close(filept);
filept = NULL;
#ifdef WANT_WIN32_UNICODE
win32_cmdline_free(argc, argv); /* This handles the premature argv == NULL, too. */
@@ -317,9 +318,10 @@ void safe_exit(int code)
split_dir_file("", &dummy, &dammy);
if(fullprogname) free(fullprogname);
#ifdef HAVE_TERMIOS
term_exit();
#if defined(NETWORK) || defined(NET123)
if(param.httpauth) free(param.httpauth);
#endif
term_exit();
exit(code);
}
@@ -478,6 +480,46 @@ static void set_appflag(char *arg, topt *opts)
{
param.appflags |= appflag;
}
#if defined(NETWORK) || defined(NET123)
static void set_httpauth(char *arg, topt *opts)
{
param.httpauth = strdup(arg);
// Do not advertise the password for all system users.
memset(arg, 'x', strlen(arg));
}
static void set_httpauth_file(char *arg, topt *opts)
{
char buf[4096];
int fd = open(arg, 0);
int good = 0;
if(fd >= 0)
{
ssize_t rdb = read(fd, buf, sizeof(buf));
// If the file filled the whole buffer, this is too much.
// realistic limits for aith are 255:255.
if(rdb > 0 && rdb < sizeof(buf))
{
buf[sizeof(buf)-1] = 0;
for(size_t i=0; i<sizeof(buf); ++i)
{
if(buf[i] == '\r' || buf[i] == '\n' || buf[i] == 0)
{
buf[i] = 0;
break;
}
}
set_httpauth(buf, opts);
good = 1;
}
close(fd);
}
if(!good)
{
error("failed to apply given auth file");
safe_exit(12);
}
}
#endif
static void list_output_modules(void)
{
@@ -597,13 +639,11 @@ topt opts[] = {
{'a', "audiodevice", GLO_ARG | GLO_CHAR, 0, &param.output_device, 0},
{'f', "scale", GLO_ARG | GLO_LONG, 0, &param.outscale, 0},
{'n', "frames", GLO_ARG | GLO_LONG, 0, &param.frame_number, 0},
#ifdef HAVE_TERMIOS
{0, "no-visual", GLO_INT, 0, &param.term_visual, FALSE},
{'C', "control", GLO_INT, 0, &param.term_ctrl, TRUE},
{0, "no-control", GLO_INT, 0, &param.term_ctrl, FALSE},
{0, "ctrlusr1", GLO_ARG | GLO_CHAR, 0, &param.term_usr1, 0},
{0, "ctrlusr2", GLO_ARG | GLO_CHAR, 0, &param.term_usr2, 0},
#endif
#ifndef NOXFERMEM
{'b', "buffer", GLO_ARG | GLO_LONG, 0, &param.usebuffer, 0},
{0, "smooth", GLO_INT, 0, &param.smooth, 1},
@@ -634,8 +674,12 @@ topt opts[] = {
{0, "cpu", GLO_ARG | GLO_CHAR, 0, &param.cpu, 0},
{0, "test-cpu", GLO_INT, 0, &runmode, TEST_CPU},
{0, "list-cpu", GLO_INT, 0, &runmode , LIST_CPU},
#ifdef NETWORK
{'u', "auth", GLO_ARG | GLO_CHAR, 0, &httpauth, 0},
#if defined(NETWORK) || defined(NET123)
#ifdef NET123
{0, "network", GLO_ARG|GLO_CHAR, 0, &param.network_backend, 0},
#endif
{'u', "auth", GLO_ARG | GLO_CHAR, set_httpauth, 0, 0},
{0, "auth-file", GLO_ARG | GLO_CHAR, set_httpauth_file, 0, 0},
#endif
#if defined (HAVE_SCHED_SETSCHEDULER) || defined (HAVE_WINDOWS_H)
/* check why this should be a long variable instead of int! */
@@ -693,91 +737,27 @@ topt opts[] = {
{0, 0, 0, 0, 0, 0}
};
static int open_track_fd (void)
{
/* Let reader handle invalid filept */
if(mpg123_open_fd(mh, filept) != MPG123_OK)
{
error2("Cannot open fd %i: %s", filept, mpg123_strerror(mh));
return 0;
}
debug("Track successfully opened.");
fresh = TRUE;
return 1;
/*1 for success, 0 for failure */
}
/* 1 on success, 0 on failure */
int open_track(char *fname)
{
filept=-1;
httpdata_reset(&htd);
if(MPG123_OK != mpg123_param(mh, MPG123_ICY_INTERVAL, 0, 0))
error1("Cannot (re)set ICY interval: %s", mpg123_strerror(mh));
mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_NO_PEEK_END, 0);
if(!strcmp(fname, "-"))
{
mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_NO_PEEK_END, 0);
filept = STDIN_FILENO;
#ifdef WIN32
_setmode(STDIN_FILENO, _O_BINARY);
#endif
}
else if (!strncmp(fname, "http://", 7)) /* http stream */
{
#if defined (WANT_WIN32_SOCKETS)
if(param.streamdump != NULL)
{
fprintf(stderr, "\nWarning: win32 networking conflicts with stream dumping. Aborting the dump.\n");
dump_close();
}
/*Use recv instead of stdio functions */
win32_net_replace(mh);
filept = win32_net_http_open(fname, &htd);
#else
filept = http_open(fname, &htd);
#endif
network_sockets_used = 1;
/* utf-8 encoded URLs might not work under Win32 */
/* now check if we got sth. and if we got sth. good */
if( (filept >= 0) && (htd.content_type.p != NULL)
&& !APPFLAG(MPG123APP_IGNORE_MIME) && !(debunk_mime(htd.content_type.p) & IS_FILE) )
{
error1("Unknown mpeg MIME type %s - is it perhaps a playlist (use -@)?", htd.content_type.p == NULL ? "<nil>" : htd.content_type.p);
error("If you know the stream is mpeg1/2 audio, then please report this as "PACKAGE_NAME" bug");
return 0;
}
if(filept < 0)
{
error1("Access to http resource %s failed.", fname);
return 0;
}
if(MPG123_OK != mpg123_param(mh, MPG123_ICY_INTERVAL, htd.icy_interval, 0))
error1("Cannot set ICY interval: %s", mpg123_strerror(mh));
if(param.verbose > 1) fprintf(stderr, "Info: ICY interval %li\n", (long)htd.icy_interval);
}
if(filept) // total paranoia
stream_close(filept);
filept = stream_open(fname);
if(!filept)
return 0;
if(param.icy_interval > 0)
/* now check if we got sth. and if we got sth. good */
if( filept->htd.content_type.p != NULL
&& !APPFLAG(MPG123APP_IGNORE_MIME) && !(debunk_mime(filept->htd.content_type.p) & IS_FILE) )
{
if(MPG123_OK != mpg123_param(mh, MPG123_ICY_INTERVAL, param.icy_interval, 0))
error1("Cannot set ICY interval: %s", mpg123_strerror(mh));
if(param.verbose > 1) fprintf(stderr, "Info: Forced ICY interval %li\n", param.icy_interval);
}
debug("OK... going to finally open.");
/* Now hook up the decoder on the opened stream or the file. */
if(filept > -1)
{
return open_track_fd();
}
else if(mpg123_open(mh, fname) != MPG123_OK)
{
error2("Cannot open %s: %s", fname, mpg123_strerror(mh));
error1("Unknown mpeg MIME type %s - is it perhaps a playlist (use -@)?", filept->htd.content_type.p == NULL ? "<nil>" : filept->htd.content_type.p);
error("If you know the stream is mpeg1/2 audio, then please report this as "PACKAGE_NAME" bug");
return 0;
}
debug("Track successfully opened.");
debug("OK... going to hook up libmpg123 and dump.");
if(dump_setup(filept, mh))
return 0;
fresh = TRUE;
return 1;
}
@@ -786,15 +766,8 @@ int open_track(char *fname)
void close_track(void)
{
mpg123_close(mh);
#if defined (WANT_WIN32_SOCKETS)
if (network_sockets_used)
win32_net_close(filept);
filept = -1;
return;
#endif
network_sockets_used = 0;
if(filept > -1) close(filept);
filept = -1;
stream_close(filept);
filept = NULL;
}
/* return 1 on success, 0 on failure */
@@ -957,9 +930,7 @@ int skip_or_die(struct timeval *start_time)
* ThOr: Yep, I deactivated the Ctrl+C hack for active control modes.
* Though, some sort of hack remains, still using intflag for track skip.
*/
#ifdef HAVE_TERMIOS
if(!param.term_ctrl)
#endif
{
struct timeval now;
unsigned long secdiff;
@@ -980,13 +951,11 @@ int skip_or_die(struct timeval *start_time)
++skip_tracks;
}
}
#ifdef HAVE_TERMIOS
else if(skip_tracks == 0)
{
debug("breaking up");
return FALSE;
}
#endif
return TRUE; /* Track advancement... no instant kill on generic/windows... */
}
#else
@@ -1100,21 +1069,18 @@ int main(int sys_argc, char ** sys_argv)
out123_del(paro);
}
#ifdef OS2
#ifdef __OS2__
_wildcard(&argc,&argv);
#endif
#ifdef HAVE_TERMIOS
// Detect terminal, enable control by default.
// Only if both input and output are connected, though. You got strange effects
// otherwise, for example mpg123 messing up settings if piping debugging output
// to another interactive program.
// Also, the playlist better not reference stdin, fighting with term_control().
int term_ctrl_default = !(term_width(STDIN_FILENO) < 0) &&
!(term_width(STDERR_FILENO) < 0);
param.term_ctrl = MAYBE;
#endif
stderr_is_term = term_width(STDERR_FILENO) >= 0;
// If either stdin or stderr look like a terminal, we enable things.
// Actually checking for terminal properties is safer than calling ctermid() here.
int stderr_width = term_width(STDERR_FILENO);
int stdin_width = term_width(STDIN_FILENO);
stderr_is_term = stderr_width >= 0;
stdin_is_term = stdin_width >= 0;
stdout_is_term = term_width(STDOUT_FILENO) >= 0;
int term_ctrl_default = stdin_is_term || stdout_is_term || stderr_is_term;
param.term_ctrl = MAYBE;
while ((result = getlopt(argc, argv, opts)))
switch (result) {
case GLO_UNKNOWN:
@@ -1177,8 +1143,6 @@ int main(int sys_argc, char ** sys_argv)
/* Don't just exit() or return out... */
/* ========================================================================================================= */
httpdata_init(&htd);
#if !defined(WIN32) && !defined(GENERIC)
if(param.remote && !param.verbose)
param.quiet = 1;
@@ -1245,9 +1209,6 @@ int main(int sys_argc, char ** sys_argv)
}
mpg123_delete_pars(mp); /* Don't need the parameters anymore ,they're in the handle now. */
/* Prepare stream dumping, possibly replacing mpg123 reader. */
if(dump_open(mh) != 0) safe_exit(78);
load_equalizer(mh);
#ifdef HAVE_SETPRIORITY
@@ -1312,6 +1273,9 @@ int main(int sys_argc, char ** sys_argv)
if(!param.remote)
prepare_playlist(argc, argv, args_utf8, &pl_utf8);
if(param.verbose > 2)
fprintf(stderr, "Note: stderr terminal width: %i\n", stderr_width);
#if !defined(WIN32) && !defined(GENERIC)
/* Remote mode is special... but normal console and terminal-controlled operation needs to catch the SIGINT.
For one it serves for track skip when not in terminal control mode.
@@ -1334,16 +1298,9 @@ int main(int sys_argc, char ** sys_argv)
ret = control_generic(mh);
safe_exit(ret);
}
#ifdef HAVE_TERMIOS
if(param.term_ctrl == MAYBE)
param.term_ctrl = (term_ctrl_default && !playlist_stdin());
if(param.term_ctrl && playlist_stdin())
{
error("no terminal control because standard input is being played");
param.term_ctrl = FALSE;
}
param.term_ctrl = term_ctrl_default;
term_init();
#endif
if(APPFLAG(MPG123APP_CONTINUE)) frames_left = param.frame_number;
while ((fname = get_next_file()))
@@ -1380,11 +1337,9 @@ int main(int sys_argc, char ** sys_argv)
got_played = -1;
if(intflag || !open_track_ret)
{
#ifdef HAVE_TERMIOS
/* We need the opportunity to cancel in case of --loop -1 . */
if(param.term_ctrl) term_control(mh, ao);
else
#endif
/* No wait for a second interrupt before we started playing. */
if(intflag) break;
@@ -1440,10 +1395,8 @@ int main(int sys_argc, char ** sys_argv)
fprintf(stderr, "\n");
}
#ifdef HAVE_TERMIOS
/* Reminder about terminal usage. */
if(param.term_ctrl) term_hint();
#endif
if(param.verbose)
{
@@ -1457,8 +1410,10 @@ int main(int sys_argc, char ** sys_argv)
, (size_p)plpos, (size_p)plfill );
print_outstr(stderr, filename, 0, stderr_is_term);
fprintf(stderr, " ...\n");
if(htd.icy_name.fill) fprintf(stderr, "ICY-NAME: %s\n", htd.icy_name.p);
if(htd.icy_url.fill) fprintf(stderr, "ICY-URL: %s\n", htd.icy_url.p);
if(filept->htd.icy_name.fill)
fprintf(stderr, "ICY-NAME: %s\n", filept->htd.icy_name.p);
if(filept->htd.icy_url.fill)
fprintf(stderr, "ICY-URL: %s\n", filept->htd.icy_url.p);
}
#if !defined(GENERIC)
{
@@ -1485,9 +1440,7 @@ int main(int sys_argc, char ** sys_argv)
/* Rethink that SIGINT logic... */
#if !defined(WIN32) && !defined(GENERIC)
#ifdef HAVE_TERMIOS
if(!param.term_ctrl)
#endif
gettimeofday (&start_time, NULL);
#endif
@@ -1519,21 +1472,14 @@ int main(int sys_argc, char ** sys_argv)
if(meta & MPG123_NEW_ID3) print_id3_tag( mh, param.long_id3
, stderr, term_width(STDERR_FILENO) );
if(meta & MPG123_NEW_ICY) print_icy(mh, stderr);
#ifdef HAVE_TERMIOS
if(!param.term_ctrl) /* Terminal user can query meta data again. */
#endif
mpg123_meta_free(mh); /* Do not waste memory after delivering. */
}
}
if(!fresh && param.verbose)
{
if(param.verbose > 1 || !(framenum & 0x7)) print_stat(mh,0,ao,1,&param);
}
#ifdef HAVE_TERMIOS
if(!param.term_ctrl) continue;
else term_control(mh, ao);
#endif
}
if(!param.smooth && !intflag)
@@ -1621,11 +1567,7 @@ static void usage(int err) /* print syntax & exit */
#endif
fprintf(o," -z shuffle play (with wildcards) -Z random play\n");
fprintf(o," -u a HTTP authentication string -E f Equalizer, data from file\n");
#ifdef HAVE_TERMIOS
fprintf(o," -C enable control keys --no-gapless not skip junk/padding in mp3s\n");
#else
fprintf(o," --no-gapless not skip junk/padding in mp3s\n");
#endif
fprintf(o," -? this help --version print name + version\n");
fprintf(o,"See the manpage "PACKAGE_NAME"(1) or call %s with --longhelp for more parameters and information.\n", prgName);
safe_exit(err);
@@ -1656,9 +1598,17 @@ static void long_usage(int err)
fprintf(o," --fuzzy Enable fuzzy seeks (guessing byte offsets or using approximate seek points from Xing TOC)\n");
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 <f> --proxy <f> set WWW proxy\n");
#else
fprintf(o," --network <b> select network backend, available: auto");
const char **nb = net123_backends;
while(*nb){ fprintf(o, " %s", *nb++); }
fprintf(o, "\n");
#endif
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");
#endif
fprintf(o," --no-seekbuffer disable seek buffer\n");
@@ -1676,7 +1626,8 @@ static void long_usage(int err)
fprintf(o," --preframes <n> number of frames to decode in advance after seeking (to keep layer 3 bit reservoir happy)\n");
fprintf(o," --resync-limit <n> Set number of bytes to search for valid MPEG data; <0 means search whole stream.\n");
fprintf(o," --streamdump <f> Dump a copy of input data (as read by libmpg123) to given file.\n");
fprintf(o," --icy-interval <n> Enforce ICY interval in bytes (for playing a stream dump.\n");
fprintf(o," --icy-interval <n> Enforce ICY interval in bytes\n");
fprintf(o," (if > 0, for playing a stream dump).\n");
fprintf(o," --ignore-streamlength Ignore header info about length of MPEG streams.\n");
fprintf(o,"\noutput/processing options\n\n");
fprintf(o," -o <o> --output <o> select audio output module\n");
@@ -1741,7 +1692,6 @@ static void long_usage(int err)
fprintf(o," -c --check count and display clipped samples\n");
fprintf(o," -v[*] --verbose increase verboselevel\n");
fprintf(o," -q --quiet quiet mode\n");
#ifdef HAVE_TERMIOS
fprintf(o," -C --control enable terminal control keys (else auto detect)\n");
fprintf(o," --no-control disable terminal control keys (disable auto detect)\n");
fprintf(o," --no-visual disable visual enhancements in output (hide cursor,\n"
@@ -1750,7 +1700,6 @@ static void long_usage(int err)
fprintf(o," (default is for stop/start)\n");
fprintf(o," --ctrlusr2 <c> control key (characer) to map to SIGUSR2\n");
fprintf(o," (default is for next track)\n");
#endif
#ifndef GENERIC
fprintf(o," --title set terminal title to filename\n");
#endif

View File

@@ -22,6 +22,8 @@
#include "win32_support.h"
#endif
#include "streamdump.h"
#if defined(WIN32) && defined(DYNAMIC_BUILD)
#define LINK_MPG123_DLL
#endif
@@ -41,6 +43,7 @@
#define VERBOSE_MAX 3
extern char* binpath; /* argv[0], actually... */
extern int stdin_is_term;
extern int stdout_is_term;
extern int stderr_is_term;
@@ -57,13 +60,11 @@ struct parameter
const char* output_module; /* audio output module to use */
const char* output_device; /* audio output device to use */
long output_flags; /* out123 flags */
#ifdef HAVE_TERMIOS
int term_ctrl;
int term_visual;
/* Those are supposed to be single characters. */
char* term_usr1;
char* term_usr2;
#endif
int checkrange;
int force_reopen;
long realtime;
@@ -109,6 +110,12 @@ struct parameter
long icy_interval;
const char* name; /* name for this player instance */
double device_buffer; /* output device buffer */
#if defined(NETWORK) || defined(NET123)
char *httpauth; /* HTTP auth data */
#endif
#if defined(NET123)
char *network_backend;
#endif
};
enum mpg123app_flags
@@ -123,8 +130,7 @@ enum mpg123app_flags
extern char *equalfile;
extern off_t framenum;
extern struct httpdata htd;
extern struct stream *filept;
extern int intflag;
#ifdef VARMODESUPPORT

69
src/net123.h Normal file
View File

@@ -0,0 +1,69 @@
/*
net123: network (HTTP(S)) streaming for mpg123 using external code
copyright 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 Thomas Orgis
This is supposed to be a binding to some system facilty to
get HTTP/HTTPS streaming going. The goal is to not be responsible
for HTTP protocol handling or even TLS in mpg123 code.
Maybe this could also stream via other protocols ... maybe even
SSH, whatever.
For POSIX platforms, this shall refer to external binaries that
do all the network stuff. For others, some system library or
other facility shall provide the minimal required functionality.
We could support seeking using HTTP ranges. But the first step is
to be able to just make a request to a certain URL and get the
server response headers followed by the data (be it a playlist file
or the MPEG stream itself).
We need to support:
- client headers (ICY yes or no, client name)
- HTTP auth parameters
The idea is that this just handles the network and protocol part
of fetching data from an URL, returning
<server response headers>
<empty line>
<stream data>
via net123_read(). Header part is with <cr><lf>, just passing through
what the server gives should be OK. The only HTTP thing mpg123 shall do
is to parse headers.
*/
#ifndef _MPG123_NET123_H_
#define _MPG123_NET123_H_
#include <sys/types.h>
// 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;
typedef struct net123_handle_struct net123_handle;
extern const char *net123_backends[];
// Open stream from URL, preparing output such that net123_read()
// later on gets the response header lines followed by one empty line
// 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);
#endif

306
src/net123_exec.c Normal file
View File

@@ -0,0 +1,306 @@
/*
net123_exec: network (HTTP(S)) streaming for mpg123 via fork+exec
This avoids linking any network code directly into mpg123, just using external
tools at runtime.
This calls wget with fallback to curl by default, one of those two
specifically if param.network_backend is set accordingly.
*/
#include "config.h"
#include "net123.h"
// for strings
#include "mpg123.h"
// Just for parameter struct that we use for HTTP auth and proxy info.
#include "mpg123app.h"
#include "compat.h"
#include "debug.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
// Those are set via environment variables:
// http_proxy
// https_proxy
// If set, the http_proxy and https_proxy variables should contain the
// URLs of the proxies for HTTP and HTTPS connections respectively.
// ftp_proxy
// same
// wget --user=... --password=...
// Alternatively: Have them in .netrc.
const char *net123_backends[] =
{
"wget"
, "curl"
, NULL
};
struct net123_handle_struct
{
int fd;
pid_t worker;
};
// Combine two given strings into one newly allocated one.
// Use: (--parameter=, value) -> --parameter=value
static char *catstr(const char *par, const char *value)
{
char *res = malloc(strlen(par)+strlen(value)+1);
if(res)
{
res[0] = 0;
strcat(res, par);
strcat(res, value);
}
return res;
}
// < 0: not checked, 0: not there, 1: present
static int got_curl = -1;
static int got_wget = -1;
static int check_program(char **argv)
{
pid_t pid = fork();
if(pid == 0)
{
int outfd = open("/dev/null", O_WRONLY);
dup2(outfd, STDOUT_FILENO);
int infd = open("/dev/null", O_RDONLY);
dup2(infd, STDIN_FILENO);
int errfd = open("/dev/null", O_WRONLY);
dup2(errfd, STDERR_FILENO);
execvp(argv[0], argv);
exit(1);
}
else if(pid > 0)
{
int stat;
if( (waitpid(pid, &stat, 0) == pid)
&& WIFEXITED(stat) && WEXITSTATUS(stat)==0 )
return 1;
}
return 0; // false, not there
}
static char **wget_argv(const char *url, const char * const * client_head)
{
const char* base_args[] =
{
"wget" // begins with program name
, "--output-document=-"
#ifndef DEBUG
, "--quiet"
#endif
, "--save-headers"
};
size_t cheads = 0;
while(client_head && client_head[cheads]){ ++cheads; }
// Get the count of argument strings right!
// Fixed args + agent + client headers [+ auth] + URL + NULL
int argc = sizeof(base_args)/sizeof(char*)+1+cheads+1+1;
char *httpauth = NULL;
char *user = NULL;
char *password = NULL;
if(param.httpauth && (httpauth = compat_strdup(param.httpauth)))
{
char *sep = strchr(httpauth, ':');
if(sep)
{
argc += 2;
*sep = 0;
user = httpauth;
password = sep+1;
}
}
char ** argv = malloc(sizeof(char*)*(argc+1));
if(!argv)
{
error("failed to allocate argv");
return NULL;
}
int an = 0;
for(;an<sizeof(base_args)/sizeof(char*); ++an)
argv[an] = compat_strdup(base_args[an]);
argv[an++] = compat_strdup("--user-agent=" PACKAGE_NAME "/" PACKAGE_VERSION);
for(size_t ch=0; ch < cheads; ++ch)
argv[an++] = catstr("--header=", client_head[ch]);
if(user)
argv[an++] = catstr("--user=", user);
if(password)
argv[an++] = catstr("--password=", password);
argv[an++] = compat_strdup(url);
argv[an++] = NULL;
return argv;
}
static char **curl_argv(const char *url, const char * const * client_head)
{
const char* base_args[] =
{
"curl" // begins with program name
#ifdef DEBUG
, "--verbose"
#endif
, "--dump-header"
, "-"
};
size_t cheads = 0;
while(client_head && client_head[cheads]){ ++cheads; }
// Get the count of argument strings right!
// Fixed args + agent + client headers [+ auth] + URL + NULL
int argc = sizeof(base_args)/sizeof(char*)+2+2*cheads+1+1;
char *httpauth = NULL;
if(param.httpauth && (httpauth = compat_strdup(param.httpauth)))
argc += 2;
char ** argv = malloc(sizeof(char*)*(argc+1));
if(!argv)
{
error("failed to allocate argv");
return NULL;
}
int an = 0;
for(;an<sizeof(base_args)/sizeof(char*); ++an)
argv[an] = compat_strdup(base_args[an]);
argv[an++] = compat_strdup("--user-agent");
argv[an++] = compat_strdup(PACKAGE_NAME "/" PACKAGE_VERSION);
for(size_t ch=0; ch < cheads; ++ch)
{
argv[an++] = compat_strdup("--header");
argv[an++] = compat_strdup(client_head[ch]);
}
if(httpauth)
{
argv[an++] = compat_strdup("--user");
argv[an++] = httpauth;
}
argv[an++] = compat_strdup(url);
argv[an++] = NULL;
return argv;
}
net123_handle *net123_open(const char *url, const char * const * client_head)
{
int use_curl = 0;
// Semi-threadsafe: The check might take place multiple times, but writing the integer
// should be safe enough.
if(!strcmp("auto",param.network_backend))
{
char *curl_argv[] = { "curl", "--version", NULL };
char *wget_argv[] = { "wget", "--version", NULL };
if(got_curl < 0)
got_curl = check_program(curl_argv);
if(got_wget < 0)
got_wget = check_program(wget_argv);
if(got_wget < 1 && got_curl == 1)
use_curl = 1;
} else if(!strcmp("curl", param.network_backend))
{
use_curl = 1;
} else if(!strcmp("wget", param.network_backend))
{
use_curl = 0;
} else
{
merror("invalid network backend specified: %s", param.network_backend);
return NULL;
}
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)
return NULL;
nh->fd = -1;
nh->worker = 0;
errno = 0;
if(pipe(fd))
{
merror("failed creating a pipe: %s", strerror(errno));
free(nh);
return NULL;
}
compat_binmode(fd[0], TRUE);
compat_binmode(fd[1], TRUE);
nh->worker = fork();
if(nh->worker == -1)
{
merror("fork failed: %s", strerror(errno));
free(nh);
return NULL;
}
if(nh->worker == 0)
{
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
int infd = open("/dev/null", O_RDONLY);
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)
exit(1);
errno = 0;
if(param.verbose > 2)
{
char **a = argv;
fprintf(stderr, "HTTP helper command:\n");
while(*a)
{
fprintf(stderr, " %s\n", *a);
++a;
}
}
#ifndef DEBUG
int errfd = open("/dev/null", O_WRONLY);
dup2(errfd, STDERR_FILENO);
#endif
execvp(argv[0], argv);
merror("cannot execute %s: %s", argv[0], strerror(errno));
exit(1);
}
// parent
if(param.verbose > 1)
fprintf(stderr, "Note: started network helper with PID %"PRIiMAX"\n", (intmax_t)nh->worker);
errno = 0;
close(fd[1]);
nh->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);
}

262
src/net123_winhttp.c Normal file
View File

@@ -0,0 +1,262 @@
#include "config.h"
#include "net123.h"
#include "compat.h"
#include "debug.h"
#include <ws2tcpip.h>
#include <winhttp.h>
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 {
HINTERNET session;
HINTERNET connect;
HINTERNET request;
URL_COMPONENTS comps;
wchar_t lpszHostName[URL_COMPONENTS_LENGTH];
wchar_t lpszUserName[URL_COMPONENTS_LENGTH];
wchar_t lpszPassword[URL_COMPONENTS_LENGTH];
wchar_t lpszUrlPath[URL_COMPONENTS_LENGTH];
wchar_t lpszExtraInfo[URL_COMPONENTS_LENGTH];
DWORD supportedAuth, firstAuth, authTarget, authTried;
char *headers;
size_t headers_pos, headers_len;
DWORD internetStatus, internetStatusLength;
LPVOID additionalInfo;
};
#define MPG123CONCAT_(x,y) x ## y
#define MPG123CONCAT(x,y) MPG123CONCAT_(x,y)
#define MPG123STRINGIFY_(x) #x
#define MPG123STRINGIFY(x) MPG123STRINGIFY_(x)
#define MPG123WSTR(x) MPG123CONCAT(L,MPG123STRINGIFY(x))
static DWORD wrap_auth(net123_handle *nh){
DWORD mode;
DWORD ret;
if(nh->comps.dwUserNameLength) {
if(!nh->authTried) {
ret = WinHttpQueryAuthSchemes(nh->request, &nh->supportedAuth, &nh->firstAuth, &nh->authTarget);
if(!ret) return GetLastError();
nh->authTried = 1;
}
mode = nh->supportedAuth & WINHTTP_AUTH_SCHEME_DIGEST ? WINHTTP_AUTH_SCHEME_DIGEST :
nh->supportedAuth & WINHTTP_AUTH_SCHEME_BASIC ? WINHTTP_AUTH_SCHEME_BASIC : 0;
/* no supported mode? */
if(!mode)
return ERROR_WINHTTP_INTERNAL_ERROR;
ret = WinHttpSetCredentials(nh->request, WINHTTP_AUTH_TARGET_SERVER, mode, nh->comps.lpszUserName, nh->comps.lpszPassword, NULL);
return GetLastError();
}
}
#if DEBUG
static void debug_crack(URL_COMPONENTS *comps){
wprintf(L"dwStructSize: %lu\n", comps->dwStructSize);
//wprintf(L"lpszScheme: %s\n", comps->lpszScheme ? comps->lpszScheme : L"null");
//wprintf(L"dwSchemeLength: %lu\n", comps->dwSchemeLength);
wprintf(L"nScheme: %u %s\n", comps->nScheme, comps->nScheme == 1 ? L"INTERNET_SCHEME_HTTP": comps->nScheme == 2 ? L"INTERNET_SCHEME_HTTPS" : L"UNKNOWN");
wprintf(L"lpszHostName: %s\n", comps->lpszHostName ? comps->lpszHostName : L"null");
wprintf(L"dwHostNameLength: %u\n", comps->dwHostNameLength);
wprintf(L"nPort: %u\n", comps->nPort);
wprintf(L"lpszUserName: %s\n", comps->lpszUserName ? comps->lpszUserName : L"null");
wprintf(L"dwUserNameLength: %lu\n", comps->dwUserNameLength);
wprintf(L"lpszPassword: %s\n", comps->lpszPassword ? comps->lpszPassword : L"null");
wprintf(L"dwPasswordLength: %lu\n", comps->dwPasswordLength);
wprintf(L"lpszUrlPath: %s\n", comps->lpszUrlPath ? comps->lpszUrlPath : L"null");
wprintf(L"dwUrlPathLength: %lu\n", comps->dwUrlPathLength);
wprintf(L"lpszExtraInfo: %s\n", comps->lpszExtraInfo? comps->lpszExtraInfo : L"null");
wprintf(L"dwExtraInfoLength: %lu\n", comps->dwExtraInfoLength);
}
#else
static void debug_crack(URL_COMPONENTS *comps){}
#endif
static
void WINAPI net123_ssl_errors(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength){
net123_handle *nh = (net123_handle *)dwContext;
nh->internetStatus = dwInternetStatus;
nh->additionalInfo = lpvStatusInformation;
nh->internetStatusLength = dwStatusInformationLength;
}
net123_handle *net123_open(const char *url, const char * const *client_head){
LPWSTR urlW = NULL, headers = NULL;
size_t ii;
WINBOOL res;
DWORD headerlen;
const LPCWSTR useragent = MPG123WSTR(PACKAGE_NAME) L"/" MPG123WSTR(PACKAGE_VERSION);
WINHTTP_STATUS_CALLBACK cb;
if(!WinHttpCheckPlatform())
return NULL;
win32_utf8_wide(url, &urlW, NULL);
if(urlW == NULL) goto cleanup;
net123_handle *ret = calloc(1, sizeof(net123_handle));
if (!ret) return ret;
ret->comps.dwStructSize = sizeof(ret->comps);
ret->comps.dwSchemeLength = 0;
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;
debug1("net123_open start crack %S", urlW);
if(!(res = WinHttpCrackUrl(urlW, 0, 0, &ret->comps))) {
debug1("net123_open crack fail %lu", GetLastError());
goto cleanup;
}
debug("net123_open crack OK");
debug_crack(&ret->comps);
ret->session = WinHttpOpen(useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
free(urlW);
urlW = NULL;
debug("net123_open WinHttpOpen OK");
if(!ret->session) goto cleanup;
debug2("net123_open WinHttpConnect %S %u", ret->comps.lpszHostName, ret->comps.nPort);
ret->connect = WinHttpConnect(ret->session, ret->comps.lpszHostName, ret->comps.nPort, 0);
if(!ret->connect) goto cleanup;
debug("net123_open WinHttpConnect OK");
debug1("WinHttpOpenRequest GET %S", ret->comps.lpszUrlPath);
ret->request = WinHttpOpenRequest(ret->connect, L"GET", ret->comps.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, ret->comps.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
if(!ret->request) goto cleanup;
debug("WinHttpOpenRequest GET OK");
cb = WinHttpSetStatusCallback(ret->request, (WINHTTP_STATUS_CALLBACK)net123_ssl_errors, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0);
if(cb == WINHTTP_INVALID_STATUS_CALLBACK){
error1("WinHttpSetStatusCallback failed to install callback, errors might not be reported properly! (%lu)", GetLastError());
}
wrap_auth(ret);
for(ii = 0; client_head[ii]; ii++){
win32_utf8_wide(client_head[ii], &headers, NULL);
if(!headers)
goto cleanup;
debug1("WinHttpAddRequestHeaders add %S", headers);
res = WinHttpAddRequestHeaders(ret->request, headers, (DWORD) -1, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE);
debug2("WinHttpAddRequestHeaders returns %u %lu", res, res ? 0 : GetLastError());
free(headers);
headers = NULL;
}
debug("net123_open ADD HEADERS OK");
res = WinHttpSendRequest(ret->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, (DWORD_PTR)ret);
if (!res) {
res = GetLastError();
error1("WinHttpSendRequest failed with %lu", res);
if(res == ERROR_WINHTTP_SECURE_FAILURE){
res = *(DWORD *)ret->additionalInfo;
error("Additionally, the ERROR_WINHTTP_SECURE_FAILURE failed with:");
if (res & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED) error(" WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED");
if (res & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT) error(" WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT");
if (res & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED) error(" WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED");
if (res & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) error(" WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA");
if (res & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) error(" WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID");
if (res & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) error(" WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID");
if (res & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR) error(" WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR");
}
goto cleanup;
}
res = WinHttpReceiveResponse(ret->request, NULL);
if (!res) {
error1("WinHttpReceiveResponse failed with %lu", GetLastError());
goto cleanup;
}
res = WinHttpQueryHeaders(ret->request, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, WINHTTP_NO_OUTPUT_BUFFER, &headerlen, WINHTTP_NO_HEADER_INDEX);
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER && headerlen > 0) {
headers = calloc(1, headerlen);
if (!headers) goto cleanup;
WinHttpQueryHeaders(ret->request, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, headers, &headerlen, WINHTTP_NO_HEADER_INDEX);
win32_wide_utf7(headers, &ret->headers, &ret->headers_len);
/* bytes written, skip the terminating null, we want to stop at the \r\n\r\n */
ret->headers_len --;
free(headers);
headers = NULL;
} else {
error("WinHttpQueryHeaders did not execute as expected");
goto cleanup;
}
debug("net123_open OK");
return ret;
cleanup:
debug("net123_open error");
if (urlW) free(urlW);
net123_close(ret);
ret = NULL;
return ret;
}
// 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){
size_t ret;
size_t to_copy = nh->headers_len - nh->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;
return ret;
}
/* is this needed? */
to_copy = bufsize > ULONG_MAX ? ULONG_MAX : bufsize;
if(!WinHttpReadData(nh->request, buf, to_copy, &bytesread)){
return EOF;
}
return bytesread;
}
// 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;
}
free(nh);
}

227
src/net123_wininet.c Normal file
View File

@@ -0,0 +1,227 @@
#include "config.h"
#include "net123.h"
#include "compat.h"
#include "debug.h"
#include <ws2tcpip.h>
#include <wininet.h>
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 {
HINTERNET session;
HINTERNET connect;
HINTERNET request;
URL_COMPONENTSW comps;
wchar_t lpszHostName[URL_COMPONENTS_LENGTH];
wchar_t lpszUserName[URL_COMPONENTS_LENGTH];
wchar_t lpszPassword[URL_COMPONENTS_LENGTH];
wchar_t lpszUrlPath[URL_COMPONENTS_LENGTH];
wchar_t lpszExtraInfo[URL_COMPONENTS_LENGTH];
wchar_t lpszScheme[URL_COMPONENTS_LENGTH];
DWORD supportedAuth, firstAuth, authTarget, authTried;
char *headers;
size_t headers_pos, headers_len;
DWORD HttpQueryInfoIndex;
DWORD internetStatus, internetStatusLength;
LPVOID additionalInfo;
};
#define MPG123CONCAT_(x,y) x ## y
#define MPG123CONCAT(x,y) MPG123CONCAT_(x,y)
#define MPG123STRINGIFY_(x) #x
#define MPG123STRINGIFY(x) MPG123STRINGIFY_(x)
#define MPG123WSTR(x) MPG123CONCAT(L,MPG123STRINGIFY(x))
#if DEBUG
static void debug_crack(URL_COMPONENTSW *comps){
wprintf(L"dwStructSize: %lu\n", comps->dwStructSize);
wprintf(L"lpszScheme: %s\n", comps->lpszScheme ? comps->lpszScheme : L"null");
wprintf(L"dwSchemeLength: %lu\n", comps->dwSchemeLength);
wprintf(L"nScheme: %u %s\n", comps->nScheme, comps->nScheme == 1 ? L"INTERNET_SCHEME_HTTP": comps->nScheme == 2 ? L"INTERNET_SCHEME_HTTPS" : L"UNKNOWN");
wprintf(L"lpszHostName: %s\n", comps->lpszHostName ? comps->lpszHostName : L"null");
wprintf(L"dwHostNameLength: %u\n", comps->dwHostNameLength);
wprintf(L"nPort: %u\n", comps->nPort);
wprintf(L"lpszUserName: %s\n", comps->lpszUserName ? comps->lpszUserName : L"null");
wprintf(L"dwUserNameLength: %lu\n", comps->dwUserNameLength);
wprintf(L"lpszPassword: %s\n", comps->lpszPassword ? comps->lpszPassword : L"null");
wprintf(L"dwPasswordLength: %lu\n", comps->dwPasswordLength);
wprintf(L"lpszUrlPath: %s\n", comps->lpszUrlPath ? comps->lpszUrlPath : L"null");
wprintf(L"dwUrlPathLength: %lu\n", comps->dwUrlPathLength);
wprintf(L"lpszExtraInfo: %s\n", comps->lpszExtraInfo? comps->lpszExtraInfo : L"null");
wprintf(L"dwExtraInfoLength: %lu\n", comps->dwExtraInfoLength);
}
#else
static void debug_crack(URL_COMPONENTSW *comps){}
#endif
static
void WINAPI net123_ssl_errors(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength){
net123_handle *nh = (net123_handle *)dwContext;
nh->internetStatus = dwInternetStatus;
nh->additionalInfo = lpvStatusInformation;
nh->internetStatusLength = dwStatusInformationLength;
}
net123_handle *net123_open(const char *url, const char * const *client_head){
LPWSTR urlW = NULL, headers = NULL;
size_t ii;
WINBOOL res;
DWORD headerlen;
const LPCWSTR useragent = MPG123WSTR(PACKAGE_NAME) L"/" MPG123WSTR(PACKAGE_VERSION);
INTERNET_STATUS_CALLBACK cb;
win32_utf8_wide(url, &urlW, NULL);
if(urlW == NULL) goto cleanup;
net123_handle *ret = calloc(1, sizeof(net123_handle));
if (!ret) return ret;
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;
debug1("net123_open start crack %S", urlW);
if(!(res = InternetCrackUrlW(urlW, 0, 0, &ret->comps))) {
debug1("net123_open crack fail %lu", GetLastError());
goto cleanup;
}
debug("net123_open crack OK");
debug_crack(&ret->comps);
ret->session = InternetOpenW(useragent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
free(urlW);
urlW = NULL;
debug("net123_open InternetOpenW OK");
if(!ret->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,
INTERNET_SERVICE_HTTP, 0, 0);
if(!ret->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;
debug("HttpOpenRequestW GET OK");
cb = InternetSetStatusCallback(ret->request, (INTERNET_STATUS_CALLBACK)net123_ssl_errors);
if(cb != NULL){
error1("InternetSetStatusCallback failed to install callback, errors might not be reported properly! (%lu)", GetLastError());
}
for(ii = 0; client_head[ii]; ii++){
win32_utf8_wide(client_head[ii], &headers, NULL);
if(!headers)
goto cleanup;
debug1("HttpAddRequestHeadersW add %S", headers);
res = HttpAddRequestHeadersW(ret->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;
}
debug("net123_open ADD HEADERS OK");
res = HttpSendRequestW(ret->request, NULL, 0, NULL, 0);
if (!res) {
res = GetLastError();
error1("HttpSendRequestW failed with %lu", res);
goto cleanup;
}
// dummy, cannot be null
headers = calloc(1,1);
headerlen = 1;
if(headers == NULL) {
error("Cannot allocate dummy buffer for HttpQueryInfoW");
goto cleanup;
}
res = HttpQueryInfoW(ret->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &ret->HttpQueryInfoIndex);
free(headers);
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);
debug3("HttpQueryInfoW returned %u, err %u : %S", res, GetLastError(), headers ? headers : L"null");
win32_wide_utf7(headers, &ret->headers, &ret->headers_len);
/* bytes written, skip the terminating null, we want to stop at the \r\n\r\n */
ret->headers_len --;
free(headers);
headers = NULL;
} else {
error("HttpQueryInfoW did not execute as expected");
goto cleanup;
}
debug("net123_open OK");
return ret;
cleanup:
debug("net123_open error");
if (urlW) free(urlW);
net123_close(ret);
ret = NULL;
return ret;
}
size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){
size_t ret;
size_t to_copy = nh->headers_len - nh->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;
return ret;
}
/* is this needed? */
to_copy = bufsize > ULONG_MAX ? ULONG_MAX : bufsize;
if(!InternetReadFile(nh->request, buf, to_copy, &bytesread)){
error1("InternetReadFile exited with %d", GetLastError());
return EOF;
}
return bytesread;
}
// 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) {
InternetCloseHandle(nh->request);
nh->request = NULL;
}
if(nh->connect) {
InternetCloseHandle(nh->connect);
nh->connect = NULL;
}
if(nh->session) {
InternetCloseHandle(nh->session);
nh->session = NULL;
}
free(nh);
}

View File

@@ -88,9 +88,6 @@ enum runmodes
static int runmode = RUN_MAIN;
int stdout_is_term = FALSE; // It's an interactive terminal.
int stderr_is_term = FALSE; // It's an interactive terminal.
static FILE* input = NULL;
static char *encoding_name = NULL;
static int encoding = MPG123_ENC_SIGNED_16;
@@ -1466,9 +1463,7 @@ static void setup_processing(void)
int main(int sys_argc, char ** sys_argv)
{
int result;
#if defined(WIN32)
_setmode(STDIN_FILENO, _O_BINARY);
#endif
compat_binmode(STDIN_FILENO, TRUE);
check_locale();
#if defined (WANT_WIN32_UNICODE)
@@ -1509,12 +1504,10 @@ int main(int sys_argc, char ** sys_argv)
out123_del(paro);
}
#ifdef OS2
#ifdef __OS2__
_wildcard(&argc,&argv);
#endif
stderr_is_term = term_width(STDERR_FILENO) >= 0;
stdout_is_term = term_width(STDOUT_FILENO) >= 0;
while ((result = getlopt(argc, argv, opts)))
switch (result) {
case GLO_UNKNOWN:

View File

@@ -18,6 +18,7 @@
#include "term.h" /* for term_restore */
#include "playlist.h"
#include "httpget.h"
#include "streamdump.h"
#include "local.h"
#include "metaprint.h"
#include <time.h> /* For srand(). */
@@ -31,9 +32,6 @@
#define SRAND srand
#endif
/* increase linebuf in blocks of ... bytes */
#define LINEBUF_STEP 100
enum playlist_type { UNKNOWN = 0, M3U, PLS, NO_LIST };
typedef struct listitem
@@ -45,7 +43,7 @@ typedef struct listitem
typedef struct playlist_struct
{
FILE* file; /* the current playlist stream */
struct stream *file; /* the current playlist stream */
size_t entry; /* entry in the playlist file */
size_t playcount; /* overall track counter for playback */
long loop; /* repeat a track n times */
@@ -60,9 +58,6 @@ typedef struct playlist_struct
enum playlist_type type;
int is_utf8; /* if we really know the contents are UTF-8-encooded */
int hit_end;
#if defined (WANT_WIN32_SOCKETS)
int sockd; /* Is Win32 socket descriptor working? */
#endif
// If the playlist itself or an input file was '-' (stdin not usable for terminal.).
int stdin_used;
} playlist_struct;
@@ -86,6 +81,11 @@ void prepare_playlist(int argc, char** argv, int args_utf8, int *is_utf8)
*/
init_playlist();
while (add_next_file(argc, argv, args_utf8)) {}
if(pl.file)
{
stream_close(pl.file);
pl.file = NULL;
}
if(param.verbose > 1)
{
fprintf(stderr, "\nplaylist in normal order:\n");
@@ -297,9 +297,6 @@ static void init_playlist(void)
pl.is_utf8 = FALSE;
pl.hit_end = FALSE;
pl.loop = param.loop;
#ifdef WANT_WIN32_SOCKETS
pl.sockd = -1;
#endif
pl.stdin_used = FALSE;
}
@@ -347,50 +344,38 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
{
size_t line_offset = 0;
pl.is_utf8 = 0; // Playlist files in env encoding (HTTP lists should be ASCII-clean).
#ifndef WANT_WIN32_SOCKETS
if (!pl.file)
#else
if (!pl.file && pl.sockd == -1)
#endif
if(!pl.file)
{
/* empty or "-" */
if (!*param.listname || !strcmp(param.listname, "-"))
pl.file = stream_open(param.listname);
if(pl.file)
{
pl.file = stdin;
pl.stdin_used = TRUE;
param.listname = NULL;
pl.entry = 0;
firstline = 1; /* just opened */
if(pl.file->fd == STDIN_FILENO)
{
pl.stdin_used = TRUE;
param.listname = NULL;
}
}
else if (!strncmp(param.listname, "http://", 7))
pl.entry = 0;
if(pl.file && pl.file->network)
{
int fd;
struct httpdata htd;
httpdata_init(&htd);
#ifndef WANT_WIN32_SOCKETS
fd = http_open(param.listname, &htd);
#else
fd = win32_net_http_open(param.listname, &htd);
#endif
debug1("htd.content_type.p: %p", (void*) htd.content_type.p);
if(!APPFLAG(MPG123APP_IGNORE_MIME) && htd.content_type.p != NULL)
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)
{
int mimi;
debug1("htd.content_type.p value: %s", htd.content_type.p);
mimi = debunk_mime(htd.content_type.p);
debug1("htd.content_type.p value: %s", pl.file->htd.content_type.p);
mimi = debunk_mime(pl.file->htd.content_type.p);
if(mimi & IS_M3U) pl.type = M3U;
else if(mimi & IS_PLS) pl.type = PLS;
if(mimi & IS_M3U)
pl.type = M3U;
else if(mimi & IS_PLS)
pl.type = PLS;
else
{
#ifndef WANT_WIN32_SOCKETS
if(fd >= 0) close(fd);
#else
if(fd != SOCKET_ERROR) win32_net_close(fd);
#endif
fd = -1;
if(mimi & IS_FILE)
{
stream_close(pl.file);
pl.file = NULL;
pl.type = NO_LIST;
if(param.listentry < 0)
{
@@ -407,257 +392,181 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
}
}
char *ptmp = NULL;
outstr(&ptmp, htd.content_type.p, 0, stderr_is_term);
outstr(&ptmp, pl.file->htd.content_type.p, 0, stderr_is_term);
error1( "Unknown playlist MIME type %s; maybe "PACKAGE_NAME
" can support it in future if you report this to the maintainer."
, PSTR(ptmp) );
free(ptmp);
stream_close(pl.file);
pl.file = NULL;
}
httpdata_free(&htd);
}
if(fd < 0)
{
param.listname = NULL;
pl.file = NULL;
#ifdef WANT_WIN32_SOCKETS
pl.sockd = -1;
#endif
error("Invalid playlist from http_open()!\n");
}
else
{
pl.entry = 0;
#ifndef WANT_WIN32_SOCKETS
pl.file = compat_fdopen(fd,"r");
#else
pl.sockd = fd;
#endif
}
}
else if (!(pl.file = compat_fopen(param.listname, "rb")))
if(!pl.file)
{
perror (param.listname);
param.listname = NULL; // why?
error("failed to open playlist file");
return 0;
}
else
{
debug("opened ordinary list file");
pl.entry = 0;
}
if (param.verbose && pl.file)
} else if(param.verbose)
{
fprintf(stderr, "Using playlist from ");
print_outstr( stderr, param.listname ? param.listname : "standard input"
, args_utf8, stderr_is_term );
fprintf(stderr, " ...\n");
}
firstline = 1; /* just opened */
}
/* reading the file line by line */
#ifndef WANT_WIN32_SOCKETS
while (pl.file)
#else
while (pl.file || (pl.sockd) != -1)
#endif
while(pl.file && stream_getline(pl.file, &pl.linebuf) > 0)
{
/*
now read a string of arbitrary size...
read a chunk, see if lineend, realloc, read another chunk
fgets reads at most size-1 bytes and always appends the \0
*/
size_t have = 0;
do
/* a bit of fuzzyness */
if(firstline)
{
/* have is the length of the string read, without the closing \0 */
if(pl.linebuf.size <= have+1)
if(pl.type == UNKNOWN)
{
if(!mpg123_resize_string(&pl.linebuf, pl.linebuf.size+LINEBUF_STEP))
if(!strcmp("[playlist]", pl.linebuf.p))
{
error("cannot increase line buffer");
break;
}
}
/* I rely on fgets writing the \0 at the end! */
#ifndef WANT_WIN32_SOCKETS
if(fgets(pl.linebuf.p+have, pl.linebuf.size-have, pl.file))
#else
if( (pl.file ? (fgets(pl.linebuf.p+have, pl.linebuf.size-have, pl.file)) : (win32_net_fgets(pl.linebuf.p+have, pl.linebuf.size-have, pl.sockd))))
#endif
{
have += strlen(pl.linebuf.p+have);
debug2("have read %lu characters into linebuf: [%s]", (unsigned long)have, pl.linebuf.p);
}
else
{
debug("fgets failed to deliver something... file ended?");
break;
}
} while(have && pl.linebuf.p[have-1] != '\r' && pl.linebuf.p[have-1] != '\n');
if(have)
{
pl.linebuf.p[strcspn(pl.linebuf.p, "\t\n\r")] = '\0';
/* a bit of fuzzyness */
if(firstline)
{
if(pl.type == UNKNOWN)
{
if(!strcmp("[playlist]", pl.linebuf.p))
{
if(param.verbose)
fprintf(stderr, "Note: detected Shoutcast/Winamp PLS playlist\n");
pl.type = PLS;
continue;
}
else if
(
(!strncasecmp("#M3U", pl.linebuf.p ,4))
||
(!strncasecmp("#EXTM3U", pl.linebuf.p ,7))
||
(param.listname != NULL && (strrchr(param.listname, '.')) != NULL && !strcasecmp(".m3u", strrchr(param.listname, '.')))
)
{
if(param.verbose) fprintf(stderr, "Note: detected M3U playlist type\n");
pl.type = M3U;
}
else
{
if(param.verbose) fprintf(stderr, "Note: guessed M3U playlist type\n");
pl.type = M3U;
}
pl.type = PLS;
continue;
}
else if
(
(!strncasecmp("#M3U", pl.linebuf.p ,4))
||
(!strncasecmp("#EXTM3U", pl.linebuf.p ,7))
||
(param.listname != NULL && (strrchr(param.listname, '.')) != NULL && !strcasecmp(".m3u", strrchr(param.listname, '.')))
)
{
if(param.verbose) fprintf(stderr, "Note: detected M3U playlist type\n");
pl.type = M3U;
}
else
{
if(param.verbose)
{
fprintf(stderr, "Note: Interpreting as ");
switch(pl.type)
{
case M3U: fprintf(stderr, "M3U"); break;
case PLS: fprintf(stderr, "PLS (Winamp/Shoutcast)"); break;
default: fprintf(stderr, "???");
}
fprintf(stderr, " playlist\n");
}
if(param.verbose) fprintf(stderr, "Note: guessed M3U playlist type\n");
pl.type = M3U;
}
firstline = 0;
}
#if !defined(WIN32)
else
{
if(param.verbose)
{
fprintf(stderr, "Note: Interpreting as ");
switch(pl.type)
{
case M3U: fprintf(stderr, "M3U"); break;
case PLS: fprintf(stderr, "PLS (Winamp/Shoutcast)"); break;
default: fprintf(stderr, "???");
}
fprintf(stderr, " playlist\n");
}
}
firstline = 0;
}
#if !defined(WIN32)
{
size_t i;
/* convert \ to / (from MS-like directory format) */
for (i=0;pl.linebuf.p[i]!='\0';i++)
{
if (pl.linebuf.p[i] == '\\') pl.linebuf.p[i] = '/';
}
}
#endif
if (pl.linebuf.p[0]=='\0') continue; /* skip empty lines... */
if (((pl.type == M3U) && (pl.linebuf.p[0]=='#')))
}
#endif
if (pl.linebuf.p[0]=='\0')
continue; // skip empty lines...
if (((pl.type == M3U) && (pl.linebuf.p[0]=='#')))
{
/* a comment line in m3u file */
if(param.listentry < 0)
{
/* a comment line in m3u file */
if(param.listentry < 0)
{
print_outstr(stdout, pl.linebuf.p, 0, stdout_is_term);
printf("\n");
}
continue;
print_outstr(stdout, pl.linebuf.p, 0, stdout_is_term);
printf("\n");
}
continue;
}
/* real filename may start at an offset */
line_offset = 0;
/* extract path out of PLS */
if(pl.type == PLS)
/* real filename may start at an offset */
line_offset = 0;
/* extract path out of PLS */
if(pl.type == PLS)
{
if(!strncasecmp("File", pl.linebuf.p, 4))
{
if(!strncasecmp("File", pl.linebuf.p, 4))
/* too lazy to really check for file number... would have to change logic to support unordered file entries anyway */
char* in_line;
if((in_line = strchr(pl.linebuf.p+4, '=')) != NULL)
{
/* too lazy to really check for file number... would have to change logic to support unordered file entries anyway */
char* in_line;
if((in_line = strchr(pl.linebuf.p+4, '=')) != NULL)
/* FileN=? */
if(in_line[1] != 0)
{
/* FileN=? */
if(in_line[1] != 0)
{
++in_line;
line_offset = (size_t) (in_line-pl.linebuf.p);
}
else
{
fprintf(stderr, "Warning: Invalid PLS line (empty filename) - corrupt playlist file?\n");
continue;
}
++in_line;
line_offset = (size_t) (in_line-pl.linebuf.p);
}
else
{
fprintf(stderr, "Warning: Invalid PLS line (no '=' after 'File') - corrupt playlist file?\n");
fprintf(stderr, "Warning: Invalid PLS line (empty filename) - corrupt playlist file?\n");
continue;
}
}
else
{
if(param.listentry < 0)
{
printf("#metainfo ");
print_outstr(stdout, pl.linebuf.p, 0, stdout_is_term);
printf("\n");
}
fprintf(stderr, "Warning: Invalid PLS line (no '=' after 'File') - corrupt playlist file?\n");
continue;
}
}
/* make paths absolute */
/* Windows knows absolute paths with c: in front... should handle this if really supporting win32 again */
if
(
(pl.dir.p != NULL)
&& (pl.linebuf.p[line_offset]!='/')
&& (pl.linebuf.p[line_offset]!='\\')
&& strncmp(pl.linebuf.p+line_offset, "http://", 7)
)
else
{
size_t need;
need = pl.dir.size + strlen(pl.linebuf.p+line_offset);
if(pl.linebuf.size < need)
if(param.listentry < 0)
{
if(!mpg123_resize_string(&pl.linebuf, need))
{
error("unable to enlarge linebuf for appending path! skipping");
continue;
}
printf("#metainfo ");
print_outstr(stdout, pl.linebuf.p, 0, stdout_is_term);
printf("\n");
}
/* move to have the space at beginning */
memmove(pl.linebuf.p+pl.dir.size-1, pl.linebuf.p+line_offset, strlen(pl.linebuf.p+line_offset)+1);
/* prepend path */
memcpy(pl.linebuf.p, pl.dir.p, pl.dir.size-1);
line_offset = 0;
}
++pl.entry;
if(param.listentry < 0)
{
printf("#entry %zu\n", pl.entry);
print_outstr(stdout, pl.linebuf.p+line_offset, 0, stdout_is_term);
printf("\n");
}
else if((param.listentry == 0) || (param.listentry == pl.entry) || APPFLAG(MPG123APP_CONTINUE))
{
add_copy_to_playlist(pl.linebuf.p+line_offset);
return 1;
continue;
}
}
else
/* make paths absolute */
/* Windows knows absolute paths with c: in front... should handle this if really supporting win32 again */
if
(
(pl.dir.p != NULL)
&& (pl.linebuf.p[line_offset]!='/')
&& (pl.linebuf.p[line_offset]!='\\')
&& strncmp(pl.linebuf.p+line_offset, "http://", 7)
&& strncmp(pl.linebuf.p+line_offset, "https://", 8)
&& strncmp(pl.linebuf.p+line_offset, "file://", 7)
)
{
if (param.listname)
if(pl.file) fclose (pl.file);
param.listname = NULL;
pl.file = NULL;
#ifdef WANT_WIN32_SOCKETS
if( pl.sockd != -1)
size_t need;
need = pl.dir.size + strlen(pl.linebuf.p+line_offset);
if(pl.linebuf.size < need)
{
win32_net_close(pl.sockd);
pl.sockd = -1;
if(!mpg123_resize_string(&pl.linebuf, need))
{
error("unable to enlarge linebuf for appending path! skipping");
continue;
}
}
#endif
/* move to have the space at beginning */
memmove(pl.linebuf.p+pl.dir.size-1, pl.linebuf.p+line_offset, strlen(pl.linebuf.p+line_offset)+1);
/* prepend path */
memcpy(pl.linebuf.p, pl.dir.p, pl.dir.size-1);
line_offset = 0;
}
++pl.entry;
if(param.listentry < 0)
{
printf("#entry %zu\n", pl.entry);
print_outstr(stdout, pl.linebuf.p+line_offset, 0, stdout_is_term);
printf("\n");
}
else if((param.listentry == 0) || (param.listentry == pl.entry) || APPFLAG(MPG123APP_CONTINUE))
{
add_copy_to_playlist(pl.linebuf.p+line_offset);
return 1;
}
}
}

View File

@@ -269,7 +269,7 @@ int open_connection(mpg123_string *host, mpg123_string *port)
{ /* Name lookup. */
if (!(myhostent = gethostbyname(host->p))) return -1;
memcpy (&myaddr, myhostent->h_addr, sizeof(myaddr));
memcpy (&myaddr, myhostent->h_addr_list[0], sizeof(myaddr));
server.sin_addr.s_addr = myaddr.s_addr;
}
else /* Just use the IP. */

View File

@@ -1,6 +1,9 @@
/*
streamdump: Dumping a copy of the input data.
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
see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Michael Hipp
@@ -11,13 +14,341 @@
#include <errno.h>
#include "debug.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
/* Stream dump descriptor. */
static int dump_fd = -1;
/* Read data from input, write copy to dump file. */
static ssize_t dump_read(int fd, void *buf, size_t count)
// Read without the buffer. This is used to fill the buffer explicitly in getline.
// This is the function that finally wraps around all the different types of input.
static ssize_t stream_read_raw(struct stream *sd, void *buf, size_t count)
{
ssize_t ret = read(fd, buf, count);
ssize_t ret = -1;
#ifdef NET123
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);
#endif
if(sd->fd >= 0) // plain file or network socket
ret = (ssize_t) unintr_read(sd->fd, buf, count);
return ret;
}
static ssize_t stream_read(struct stream *sd, void *buf, size_t count)
{
if(!sd)
return -1;
char *bbuf = buf;
ssize_t ret = 0;
if(count > SSIZE_MAX)
return -1;
while(count)
{
size_t get = 0;
if(sd->fill)
{ // drain the buffer
get = sd->fill > count ? count : sd->fill;
memcpy(bbuf, sd->bufp, get);
sd->fill -= get;
sd->bufp += get;
} else
{ // get it from the source
ssize_t rret = stream_read_raw(sd, bbuf, count);
if(rret < 0)
return ret > 0 ? ret : -1;
if(rret == 0)
return ret;
get = rret;
}
bbuf += get;
count -= get;
ret += get;
}
return ret;
}
static off_t stream_seek(struct stream *sd, off_t pos, int whence)
{
if(!sd || sd->network)
return -1;
return lseek(sd->fd, pos, whence);
}
// Read into the stream buffer, look for line endings there, copy stuff.
// This should work with \n and \r\n sequences ... even just \r sequences?
// Yes, either \r or \n ends a line, a following \n or \r is just swallowed.
// Need to catch the case where the buffer ends with \r and the next buffer
// contents start with the matching \n, and the other way round.
ssize_t stream_getline(struct stream *sd, mpg123_string *line)
{
if(!sd || !line)
return -1;
line->fill = 0; // this is EOF
char lend = 0;
while(1)
{
mdebug("getline loop with %d", sd->fill);
// If we got just an \r, we need to ensure that we swalloed the matching \n,
// too. This implies that we got a line stored already.
if(sd->fill && lend)
{
// finish skipping over an earlier line end
if( (*sd->bufp == '\n' || *sd->bufp == '\r') && *sd->bufp != lend)
{
++sd->bufp;
--sd->fill;
}
// whatever happened, no half-line-end lurking anymore
return line->fill;
}
if(sd->fill)
{
// look for line end here, copy things
size_t i = 0;
while(i < sd->fill && sd->bufp[i] != '\n' && sd->bufp[i] != '\r')
++i;
// either found an end, or hit the end
if(!mpg123_add_substring(line, sd->bufp, 0, i))
return -1; // out of memory
// skip over a line end if found
if(i == sd->fill)
{
// not done yet, refill, please
sd->fill = 0;
} else
{
// got end and stored complete line, but need to go on to capture full line end
lend = sd->bufp[i]; // either \r or \n
sd->bufp += i+1;
sd->fill -= i+1;
}
} else
{
debug("re-filling buffer");
// refill buffer
ssize_t ret = stream_read_raw(sd, sd->buf, sizeof(sd->buf));
mdebug("raw read return: %zd", ret);
if(ret < 0)
return -1;
else if(ret == 0)
return line->fill; // A line ends at end of file.
else
{
sd->fill = ret;
sd->bufp = sd->buf;
}
}
}
}
int stream_parse_headers(struct stream *sd)
{
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 hn = sizeof(head)/sizeof(char*);
int hi = -1;
int got_ok = 0;
debug("parsing headers");
while(stream_getline(sd, &line) > 0)
{
mdebug("HTTP in: %s", line.p);
if(line.p[0] == 0)
{
break; // This is the content separator line.
}
// 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.
if(!strncasecmp("http/", line.p, 5))
{
// HTTP/1.1 200 OK
char *tok = line.p;
while(*tok && *tok != ' ' && *tok != '\t')
++tok;
while(*tok && (*tok == ' ' || *tok == '\t'))
++tok;
if(tok && *tok != '2')
{
merror("HTTP error response: %s", line.p);
ret = -1;
break;
} else if(tok && *tok == '2')
{
if(param.verbose > 2)
fprintf(stderr, "Note: got a positive HTTP response\n");
got_ok = 1;
}
}
if(hi >= 0 && (line.p[0] == ' ' || line.p[0] == '\t'))
{
debug("header continuation");
// nh continuation line, appending to already stored value.
char *v = line.p+1;
while(*v == ' ' || *v == '\t'){ ++v; }
if(!mpg123_add_string(val[hi], v))
{
merror("failed to grow header value for %s", head[hi]);
hi = -1;
continue;
}
}
char *n = line.p;
char *v = strchr(line.p, ':');
if(!v)
continue; // No proper header line.
// Got a header line.
*v = 0; // Terminate the header name.
if(param.verbose > 2)
fprintf(stderr, "Note: got header: %s\n", n);
++v; // Value starts after : and whitespace.
while(*v == ' ' || *v == '\t'){ ++v; }
for(hi = 0; hi<hn; ++hi)
{
if(!strcasecmp(n, head[hi]))
break;
}
if(hi == hn)
{
debug("skipping uninteresting header");
hi = -1;
continue;
}
if(param.verbose > 2)
fprintf(stderr, "Note: storing HTTP header %s: %s\n", head[hi], v);
got_ok = 1; // When we got some header to store, things seem fine.
if(!mpg123_set_string(val[hi], v))
{
error("failed to allocate header value storage");
hi = -1;
continue;
}
}
if(icyint.fill)
{
sd->htd.icy_interval = atol(icyint.p);
if(param.verbose > 1)
fprintf(stderr, "Info: ICY interval %li\n", (long)sd->htd.icy_interval);
}
if(!got_ok)
{
error("missing positive server response");
ret = -1;
}
mpg123_free_string(&icyint);
mpg123_free_string(&line);
return ret;
}
static void stream_init(struct stream *sd)
{
sd->bufp = sd->buf;
sd->fill = 0;
sd->network = 0;
sd->fd = -1;
#ifdef NET123
sd->nh = NULL;
#endif
httpdata_init(&sd->htd);
}
struct stream *stream_open(const char *url)
{
struct stream *sd = malloc(sizeof(struct stream));
if(!sd)
return NULL;
stream_init(sd);
mdebug("opening resource %s", url);
if(!strcmp(url, "-"))
{
sd->fd = STDIN_FILENO;
compat_binmode(STDIN_FILENO, TRUE);
}
else if(!strncasecmp("file://", url, 7))
url+= 7; // use local file access for files, the scheme may be useful
#ifdef NET123
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;
mpg123_string accept;
mpg123_init_string(&accept);
append_accept(&accept);
client_head[1] = accept.p;
sd->nh = net123_open(url, client_head);
if(stream_parse_headers(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;
}
}
#endif
else
{
// plain file access
errno = 0;
sd->fd = compat_open(url, O_RDONLY|O_BINARY);
if(sd->fd < 0)
{
merror("failed to open file: %s", strerror(errno));
stream_close(sd);
return NULL;
}
}
return sd;
}
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);
free(sd);
}
/* Read data from input, write copy to dump file. */
static ssize_t dump_read(void *handle, void *buf, size_t count)
{
struct stream *sd = handle;
ssize_t ret = stream_read(sd, buf, count);
if(ret > 0 && dump_fd > -1)
{
ret = unintr_write(dump_fd, buf, ret);
@@ -26,9 +357,10 @@ static ssize_t dump_read(int fd, void *buf, size_t count)
}
/* Also mirror seeks, to prevent messed up dumps of seekable streams. */
static off_t dump_seek(int fd, off_t pos, int whence)
static off_t dump_seek(void *handle, off_t pos, int whence)
{
off_t ret = lseek(fd, pos, whence);
struct stream *sd = handle;
off_t ret = stream_seek(sd, pos, whence);
if(ret >= 0 && dump_fd > -1)
{
ret = lseek(dump_fd, pos, whence);
@@ -37,30 +369,62 @@ static off_t dump_seek(int fd, off_t pos, int whence)
}
/* External API... open and close. */
int dump_open(mpg123_handle *mh)
int dump_setup(struct stream *sd, mpg123_handle *mh)
{
int ret;
int ret = MPG123_OK;
int do_replace = 0; // full replacement with handle
if(param.streamdump == NULL) return 0;
if(!param.quiet) fprintf(stderr, "Note: Dumping stream to %s\n", param.streamdump);
dump_fd = compat_open(param.streamdump, O_CREAT|O_TRUNC|O_RDWR);
if(dump_fd < 0)
// paranoia: if buffer active, ensure handle I/O
if(sd->fill)
do_replace = 1;
#ifdef NET123
if(sd->nh)
do_replace = 1;
#endif
if(param.streamdump)
{
error1("Failed to open dump file: %s\n", strerror(errno));
return -1;
do_replace = 1;
// open freshly or keep open
if(dump_fd < 0)
{
if(!param.quiet)
fprintf(stderr, "Note: Dumping stream to %s\n", param.streamdump);
dump_fd = compat_open(param.streamdump, O_CREAT|O_TRUNC|O_RDWR);
}
if(dump_fd < 0)
{
error1("Failed to open dump file: %s\n", strerror(errno));
return -1;
}
#ifdef WIN32
_setmode(dump_fd, _O_BINARY);
#endif
}
#ifdef WIN32
_setmode(dump_fd, _O_BINARY);
#endif
if( MPG123_OK != mpg123_param(mh, MPG123_ICY_INTERVAL
, param.icy_interval ? param.icy_interval : sd->htd.icy_interval, 0) )
error1("Cannot set ICY interval: %s", mpg123_strerror(mh));
if(param.icy_interval > 0 && param.verbose > 1)
fprintf(stderr, "Info: Forced ICY interval %li\n", param.icy_interval);
ret = mpg123_replace_reader(mh, dump_read, dump_seek);
if(do_replace)
{
mpg123_replace_reader_handle(mh, dump_read, dump_seek, NULL);
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);
ret = mpg123_open_fd(mh, sd->fd);
}
if(ret != MPG123_OK)
{
error1("Unable to replace reader for stream dump: %s\n", mpg123_strerror(mh));
dump_close();
error1("Unable to replace reader/open track for stream dump: %s\n", mpg123_strerror(mh));
dump_close(sd);
return -1;
}
else return 0;

View File

@@ -1,9 +1,13 @@
/*
streamdump: Dumping a copy of the input data.
streamdump: I/O interposing for reading input streams
copyright 2010 by the mpg123 project - free software under the terms of the LGPL 2.1
This initially was about dumping a copy of the input data, as read
by libmpg123. Now it is a generic interposer to wrap around plain file
and network stream reading.
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
initially written by Thomas Orgis
*/
#ifndef STREAMDUMP_H
@@ -11,10 +15,39 @@
#include "mpg123app.h"
/* Open dump stream, if requested, and replace readers.
Return value is 0 for no error, -1 when bad. */
int dump_open(mpg123_handle *mh);
/* Just close... */
void dump_close(void);
#ifdef NET123
#include "net123.h"
#endif
// The stream is either addressed via file descriptor or net123 handle.
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
net123_handle *nh; // if != null: a net123 stream
#endif
};
// Open a stream resource, creating and returning a new handle.
struct stream * stream_open(const char *url);
// Read lines, with arbitrary line end, which is stripped.
// Return number of bytes in line (including closing zero byte) or error < 0.
// End of file returns zero, consequently.
ssize_t stream_getline(struct stream *sd, mpg123_string *line);
void stream_close(struct stream *sd);
// Use an open stream object to optionally prepare the dump and
// link up input to the mpg123 handle.
// Can be called repeatedly to switch input methods with new
// stream objects, but keeping a stream dump file open.
// Return value is 0 for no error, -1 when bad.
int dump_setup(struct stream *sd, mpg123_handle *mh);
// Just close the dump output, not touching anything else.
void dump_close();
#endif

View File

@@ -7,33 +7,20 @@
*/
#include "mpg123app.h"
#ifdef HAVE_TERMIOS
#include <termios.h>
#include <ctype.h>
#include "term.h"
#include "terms.h"
#include "common.h"
#include "playlist.h"
#include "metaprint.h"
#include "debug.h"
static int term_enable = 0;
// We can work with the terminal either via stdin or stderr.
// It can be that only one side is hooked to an interactive terminal.
// You should be able to pipe terminal control commands (for testing)
// and still have proper display.
static int term_fd = -1;
static struct termios old_tio;
int seeking = FALSE;
extern out123_handle *ao;
/* Buffered key from a signal or whatnot.
We ignore the null character... */
static char prekey = 0;
/* 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; };
@@ -66,50 +53,16 @@ struct keydef term_help[] =
,{ MPG123_BOOKMARK_KEY, 0, "print out current position in playlist and track, for the benefit of some external tool to store bookmarks" }
,{ 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_BASS_UP_KEY, 0, "more bass" }
,{ MPG123_BASS_DOWN_KEY, 0, "less bass" }
,{ MPG123_MID_UP_KEY, 0, "more mids" }
,{ MPG123_MID_DOWN_KEY, 0, "less mids" }
,{ MPG123_TREBLE_UP_KEY, 0, "more treble" }
,{ MPG123_TREBLE_DOWN_KEY, 0, "less treble" }
};
void term_sigcont(int sig);
static void term_sigusr(int sig);
/* This must call only functions safe inside a signal handler. */
int term_setup(struct termios *pattern)
{
mdebug("setup on fd %d", term_fd);
struct termios tio = *pattern;
/* One might want to use sigaction instead. */
signal(SIGCONT, term_sigcont);
signal(SIGUSR1, term_sigusr);
signal(SIGUSR2, term_sigusr);
tio.c_lflag &= ~(ICANON|ECHO);
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
return tcsetattr(term_fd,TCSANOW,&tio);
}
void term_sigcont(int sig)
{
term_enable = 0;
if (term_setup(&old_tio) < 0)
{
fprintf(stderr,"Can't set terminal attributes\n");
return;
}
term_enable = 1;
}
static void term_sigusr(int sig)
{
switch(sig)
{
case SIGUSR1: prekey=*param.term_usr1; break;
case SIGUSR2: prekey=*param.term_usr2; break;
}
}
/* initialze terminal */
void term_init(void)
{
@@ -124,19 +77,15 @@ void term_init(void)
return;
term_enable = 0;
if( tcgetattr(term_fd=STDERR_FILENO,&old_tio) < 0
&& tcgetattr(term_fd=STDIN_FILENO,&old_tio) < 0 )
errno = 0;
if(term_setup() < 0)
{
fprintf(stderr,"Can't get terminal attributes\n");
if(errno)
merror("failed to set up terminal: %s", strerror(errno));
else
error("failed to set up terminal");
return;
}
if(term_setup(&old_tio) < 0)
{
fprintf(stderr,"Can't set terminal attributes\n");
return;
}
term_enable = 1;
}
@@ -255,41 +204,10 @@ static void seekmode(mpg123_handle *mh, out123_handle *ao)
}
}
/* Get the next pressed key, if any.
Returns 1 when there is a key, 0 if not. */
static int get_key(int do_delay, char *val)
{
fd_set r;
struct timeval t;
/* Shortcut: If some other means sent a key, use it. */
if(prekey)
{
debug1("Got prekey: %c\n", prekey);
*val = prekey;
prekey = 0;
return 1;
}
t.tv_sec=0;
t.tv_usec=(do_delay) ? 10*1000 : 0;
FD_ZERO(&r);
FD_SET(STDIN_FILENO,&r);
if(select(1,&r,NULL,NULL,&t) > 0 && FD_ISSET(0,&r))
{
if(read(STDIN_FILENO,val,1) <= 0)
return 0; /* Well, we couldn't read the key, so there is none. */
else
return 1;
}
else return 0;
}
static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val)
{
debug1("term_handle_key: %c", val);
switch(tolower(val))
switch(val)
{
case MPG123_BACK_KEY:
out123_pause(ao);
@@ -314,7 +232,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,&param);
stopped = 0;
out123_pause(ao); /* no chance for annoying underrun warnings */
out123_drop(ao);
@@ -389,14 +309,48 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val)
offset+=50;
break;
case MPG123_VOL_UP_KEY:
mpg123_volume_change(fr, 0.02);
mpg123_volume_change_db(fr, +1);
break;
case MPG123_VOL_DOWN_KEY:
mpg123_volume_change(fr, -0.02);
mpg123_volume_change_db(fr, -1);
break;
case MPG123_VOL_MUTE_KEY:
set_mute(ao, muted=!muted);
break;
case MPG123_EQ_RESET_KEY:
mpg123_reset_eq(fr);
break;
case MPG123_EQ_SHOW_KEY:
{
if(param.verbose)
print_stat(fr,0,ao,0,&param);
// Assuming only changes happen via terminal control, these 3 values
// are what counts.
fprintf( stderr, "\n\nbass: %.3f\nmid: %.3f\ntreble: %.3f\n\n"
, mpg123_geteq(fr, MPG123_LEFT, 0)
, mpg123_geteq(fr, MPG123_LEFT, 1)
, mpg123_geteq(fr, MPG123_LEFT, 2)
);
}
break;
case MPG123_BASS_UP_KEY:
mpg123_eq_change(fr, MPG123_LR, 0, 0, +1);
break;
case MPG123_BASS_DOWN_KEY:
mpg123_eq_change(fr, MPG123_LR, 0, 0, -1);
break;
case MPG123_MID_UP_KEY:
mpg123_eq_change(fr, MPG123_LR, 1, 1, +1);
break;
case MPG123_MID_DOWN_KEY:
mpg123_eq_change(fr, MPG123_LR, 1, 1, -1);
break;
case MPG123_TREBLE_UP_KEY:
mpg123_eq_change(fr, MPG123_LR, 2, 31, +1);
break;
case MPG123_TREBLE_DOWN_KEY:
mpg123_eq_change(fr, MPG123_LR, 2, 31, -1);
break;
case MPG123_PITCH_UP_KEY:
case MPG123_PITCH_BUP_KEY:
case MPG123_PITCH_DOWN_KEY:
@@ -460,7 +414,6 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val)
print_stat(fr,0,ao,0,&param);
fprintf(stderr, "%s\n", param.verbose ? "\n" : "");
print_id3_tag(fr, param.long_id3, stderr, term_width(STDERR_FILENO));
fprintf(stderr, "\n");
break;
case MPG123_MPEG_KEY:
if(param.verbose)
@@ -555,7 +508,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(get_key(do_delay, &val))
while(term_get_key(do_delay, &val))
{
term_handle_key(fr, ao, val);
}
@@ -571,9 +524,5 @@ void term_exit(void)
if(!term_enable) return;
debug("reset attrbutes");
tcsetattr(term_fd,TCSAFLUSH,&old_tio);
term_restore();
}
#endif

View File

@@ -12,8 +12,6 @@
#include "mpg123app.h"
#include "audio.h"
#ifdef HAVE_TERMIOS
#define LOOP_CYCLES 0.500000 /* Loop time in sec */
/*
@@ -58,6 +56,16 @@
#define MPG123_PITCH_DOWN_KEY 'x'
#define MPG123_PITCH_BDOWN_KEY 'X'
#define MPG123_PITCH_ZERO_KEY 'w'
#define MPG123_EQ_RESET_KEY 'e'
#define MPG123_EQ_SHOW_KEY 'E'
#define MPG123_BASS_UP_KEY 'A'
#define MPG123_BASS_DOWN_KEY 'a'
#define MPG123_MID_UP_KEY 'J'
#define MPG123_MID_DOWN_KEY 'j'
#define MPG123_TREBLE_UP_KEY 'N'
#define MPG123_TREBLE_DOWN_KEY 'n'
#define MPG123_BOOKMARK_KEY 'k'
/* This counts as "undocumented" and can disappear */
#define MPG123_FRAME_INDEX_KEY 'i'
@@ -85,5 +93,3 @@ off_t term_control(mpg123_handle *mh, out123_handle *ao);
void term_hint(void); /* Print a message hinting at terminal usage. */
#endif
#endif

31
src/term_none.c Normal file
View File

@@ -0,0 +1,31 @@
/*
term_none: no-op terminal, nothing at all
copyright 2008-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 Thomas Orgis and Jonathan Yong
*/
int term_have_fun(int fd, int want_visuals)
{
return 0;
}
int term_width(int fd)
{
return -1;
}
int term_setup(void)
{
return -1;
}
void term_restore(void)
{
}
int term_get_key(int do_delay, char *val)
{
return 0;
}

229
src/term_posix.c Normal file
View File

@@ -0,0 +1,229 @@
/*
term_posix: POSIX-specifc terminal functionality
HAVE_TERMIOS is a prerequisite.
copyright 2008-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 Thomas Orgis
*/
#include "config.h"
#ifdef __OS2__
// Hoping for properly working termios in some future (?!), but until then,
// we need keyboard access bypassing that.
#define INCL_KBD
#define INCL_DOSPROCESS
#include <os2.h>
#endif
#include "compat.h"
#ifndef HAVE_TERMIOS
#error "No TERMIOS? Here?"
#endif
// for param struct
#include "mpg123app.h"
#include <termios.h>
#include <sys/ioctl.h>
#include "terms.h"
#include "debug.h"
static int term_is_fun = -1;
// This now always refers to a ;freshly opened terminal descriptor (e.g. /dev/tty).
// Printouts to stderr are independent of this.
static int term_fd = -1;
static struct termios old_tio;
/* Buffered key from a signal or whatnot.
We ignore the null character... */
static char prekey = 0;
int term_have_fun(int fd, int want_visuals)
{
if(term_is_fun > -1)
return term_is_fun;
else
term_is_fun = 0;
if(term_width(fd) > 0 && want_visuals)
{
/* Only play with non-dumb terminals. */
char *tname = compat_getenv("TERM");
if(tname)
{
if(strcmp(tname, "") && strcmp(tname, "dumb"))
term_is_fun = 1;
free(tname);
}
}
return term_is_fun;
}
/* Also serves as a way to detect if we have an interactive terminal. */
int term_width(int fd)
{
#ifdef __OS2__
int s[2];
_scrsize (s);
// It seems like we cannot really use the last character of the
// term and have to stop one short to avoid advancing a line.
if (s[0] >= 0)
return s[0] - 1;
#else
struct winsize geometry;
geometry.ws_col = 0;
if(ioctl(fd, TIOCGWINSZ, &geometry) >= 0)
return (int)geometry.ws_col;
#endif
return -1;
}
static int term_setup_detail(struct termios *pattern);
static void term_sigcont(int sig)
{
if(term_setup_detail(&old_tio) < 0)
{
debug("Can't set terminal attributes");
return;
}
}
static void term_sigusr(int sig)
{
switch(sig)
{
case SIGUSR1: prekey=*param.term_usr1; break;
case SIGUSR2: prekey=*param.term_usr2; break;
}
}
/* This must call only functions safe inside a signal handler. */
static int term_setup_detail(struct termios *pattern)
{
mdebug("setup on fd %d", term_fd);
/* One might want to use sigaction instead. */
signal(SIGCONT, term_sigcont);
signal(SIGUSR1, term_sigusr);
signal(SIGUSR2, term_sigusr);
struct termios tio = *pattern;
tio.c_lflag &= ~(ICANON|ECHO);
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
#ifdef __OS2__
// Do not care for the error until OS/2 is known to work.
tcsetattr(term_fd,TCSANOW,&tio);
return 0;
#else
return tcsetattr(term_fd,TCSANOW,&tio);
#endif
}
int term_setup(void)
{
if(term_fd < 0)
{
const char *term_name;
#ifdef HAVE_CTERMID
term_name = ctermid(NULL);
#else
term_name = "/dev/tty";
#endif
if(term_name)
mdebug("accessing terminal for control via %s", term_name);
else
{
error("no controlling terminal");
return -1;
}
term_fd = open(term_name, O_RDONLY);
if(term_fd < 0)
{
merror("failed to open terminal: %s", strerror(errno));
return -1;
}
}
if(tcgetattr(term_fd, &old_tio) < 0)
{
// For now, this always fails on OS/2, but they might fix things.
// So just try to move on.
#ifndef __OS2__
merror("failed to get terminal attributes: %s", strerror(errno));
return -1;
#endif
}
errno = 0;
if(term_setup_detail(&old_tio) < 0)
{
close(term_fd);
term_fd = -1;
if(errno)
merror("failure setting terminal attributes: %s", strerror(errno));
else
error("failure setting terminal attributes");
return -1;
}
return 0;
}
/* 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)
{
#ifdef __OS2__
KBDKEYINFO key;
key.chChar = 0;
key.chScan = 0;
if(do_delay)
DosSleep(10);
if(!KbdCharIn(&key,IO_NOWAIT,0) && key.chChar)
{
*val = key.chChar;
return 1;
}
#else
fd_set r;
struct timeval t;
/* Shortcut: If some other means sent a key, use it. */
if(prekey)
{
debug1("Got prekey: %c\n", prekey);
*val = prekey;
prekey = 0;
return 1;
}
t.tv_sec=0;
t.tv_usec=(do_delay) ? 10*1000 : 0;
FD_ZERO(&r);
FD_SET(term_fd,&r);
if(select(term_fd+1,&r,NULL,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. */
else
return 1;
}
#endif
else return 0;
}
void term_restore(void)
{
debug("reset attrbutes");
tcsetattr(term_fd,TCSAFLUSH,&old_tio);
if(term_fd > -1)
close(term_fd);
term_fd = -1;
}

113
src/term_win32.c Normal file
View File

@@ -0,0 +1,113 @@
/*
term_win32: Windows-specifc terminal functionality
This is a very lightweight terminal library, just the minimum to
- get at the width of the terminal (if there is one)
- be able to read single keys being pressed for control
- maybe also switch of echoing of input
copyright 2008-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 Thomas Orgis and Jonathan Yong
*/
#include "config.h"
#include "compat.h"
#include "terms.h"
#define WIN32_LEAN_AND_MEAN 1
#include <io.h>
#include <ctype.h>
#include <windows.h>
#include <wincon.h>
#include "debug.h"
static HANDLE consoleintput = INVALID_HANDLE_VALUE;
static HANDLE consoleoutput = INVALID_HANDLE_VALUE;
static HANDLE getconsoleintput(void){
DWORD mode, r;
if(consoleintput == INVALID_HANDLE_VALUE){
consoleintput = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(consoleintput == INVALID_HANDLE_VALUE || consoleintput == NULL)
return consoleintput;
GetConsoleMode(consoleintput, &mode);
mode |= ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_WINDOW_INPUT;
mode &= ~(ENABLE_ECHO_INPUT|ENABLE_QUICK_EDIT_MODE|ENABLE_MOUSE_INPUT);
SetConsoleMode(consoleintput, mode);
}
return consoleintput;
}
static HANDLE getconsole(void){
if(consoleoutput == INVALID_HANDLE_VALUE){
consoleoutput = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
}
return consoleoutput;
}
// No fun for windows until we reorganize control character stuff.
int term_have_fun(int fd, int want_visuals)
{
return 0;
}
static DWORD lastmode;
int term_setup(void)
{
return 0;
}
void term_restore(void){
CloseHandle(consoleintput);
CloseHandle(consoleoutput);
consoleintput = INVALID_HANDLE_VALUE;
consoleoutput = INVALID_HANDLE_VALUE;
}
int term_width(int fd)
{
CONSOLE_SCREEN_BUFFER_INFO pinfo;
HANDLE h;
h = getconsole();
if(h == INVALID_HANDLE_VALUE || h == NULL)
return -1;
if(GetConsoleScreenBufferInfo(h, &pinfo))
// One less than actual width, as Terminal advances
// to next line with the last character.
return pinfo.dwMaximumWindowSize.X -1;
return -1;
}
int term_present(void){
return GetConsoleWindow() ? 1 : 0;
}
/* 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){
INPUT_RECORD record;
HANDLE input;
DWORD res;
input = getconsoleintput();
if(input == NULL || input == INVALID_HANDLE_VALUE)
return 0;
while(WaitForSingleObject(input, do_delay ? 10 : 0) == WAIT_OBJECT_0){
do_delay = 0;
if(!ReadConsoleInput(input, &record, 1, &res))
return 0;
if(record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown){
*val = record.Event.KeyEvent.uChar.AsciiChar;
return 1;
}
}
return 0;
}

52
src/terms.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef H_TERMS
#define H_TERMS
/*
terms: terminal specifics
This is a very lightweight terminal library, just the minimum to
- get at the width of the terminal (if there is one)
- be able to read single keys being pressed for control
- maybe also switch off echoing of input
copyright 2008-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 Thomas Orgis and Jonathan Yong
*/
/* These two functions query terminal properties based on a terminal
being connected to the specified file descriptor (either STDIN_FILENO
or STDERR_FILENO). */
/* Return non-zero if full terminal fun is desired/possible. */
int term_have_fun(int fd, int want_visuals);
/* Return width of terminal associated with given descriptor,
-1 when there is none. */
int term_width(int fd);
/*
This is for more serious work with the terminal: It is sensible to
open some internal handle and continue to operate on that on subsequent
calls.
*/
/** Setup terminal for control work (things like disabling echo and
* buffering. You handle your handles internally.
* \return 0 on suceess, -1 on trouble
*/
int term_setup(void);
/** Restore terminal properties to what they were before we messed
* around. Failure is not an option.
*/
void term_restore(void);
/** Check for and return a key press event.
* \param do_delay Wait for up to 10 ms for a key event if true.
* \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);
#endif

View File

@@ -396,7 +396,7 @@ static int win32_net_resolve_redirect(mpg123_string *response, mpg123_string *re
return TRUE;
}
int win32_net_http_open(char* url, struct httpdata *hd)
int win32_net_http_open(const char* url, struct httpdata *hd)
{
mpg123_string purl, host, port, path;
mpg123_string request, response, request_url;
@@ -600,7 +600,7 @@ exit: /* The end as well as the exception handling point... */
return 1;
}
#else
int win32_net_http_open(char* url, struct httpdata *hd)
int win32_net_http_open(const char* url, struct httpdata *hd)
{
return -1;
}

View File

@@ -40,7 +40,7 @@ so the socket handle is always associated with the last call to win32_net_http_o
* @param[out] hd http data info
* @return -1 for failure, 1 for success
*/
int win32_net_http_open(char* url, struct httpdata *hd);
int win32_net_http_open(const char* url, struct httpdata *hd);
/**
* Reads from network socket