mpg123-1.30.0
This commit is contained in:
20
INSTALL
20
INSTALL
@@ -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
|
||||
|
||||
122
Makefile.in
122
Makefile.in
@@ -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
46
NEWS
@@ -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
|
||||
|
||||
@@ -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
501
configure
vendored
@@ -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
|
||||
|
||||
270
configure.ac
270
configure.ac
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
243
doc/windows-notes.html
Normal 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 “<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” 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 “1.26.4” </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 “32” or “64”
|
||||
bit.. Extract the entire downloaded zip. Consider creating a new
|
||||
target directory named MPG123 in “Program Files”. 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
|
||||
…</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: “F:\Music\*.mp3”.
|
||||
</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 “Device Manager”
|
||||
(devmgmt.msc). Click to expand “Sound, video and game
|
||||
controllers”. Identify the desired sound device and
|
||||
double-click or right click to “Properties”. Select the
|
||||
“Details” tab, and look for Property “Device
|
||||
instance path” (Win 10) or “Device instance id”
|
||||
(Win XP). The “Value” box will contain one or more
|
||||
lines- the first line is the one you want- and looks something like
|
||||
this: USB\VID_0D8C&PID_0014&MI_00\6&175BA917&0&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 > Environment Variables > 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 “Music on Hold” 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’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 “Music On Hold”. 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 ("G:\music on hold\*.mp3") do (</p>
|
||||
<p class="western" align="left" style="margin-bottom: 0in; line-height: 100%">
|
||||
mpg123 -m -a %Sabrent% ^"%%f^" ))</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 “PLAYEM >
|
||||
nul 2>&1” 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>
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
32
src/common.c
32
src/common.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
@@ -422,12 +419,14 @@ int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *por
|
||||
|
||||
/* Acceptance, stream setup. */
|
||||
if( !append_accept(request)
|
||||
|| !mpg123_add_string(request, "\r\n")
|
||||
|| !mpg123_add_string(request, CONN_HEAD)
|
||||
|| !mpg123_add_string(request, icy) )
|
||||
|| !mpg123_add_string(request, 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.");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -181,6 +199,12 @@ int open_os2(out123_handle *ao)
|
||||
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;
|
||||
@@ -325,12 +349,31 @@ int open_os2(out123_handle *ao)
|
||||
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)
|
||||
{
|
||||
int written = 0;
|
||||
struct prebuf *pb = ao->userptr;
|
||||
mdebug("write_os2(%p, %p, %d)", ao, buf, len);
|
||||
while(len > 0)
|
||||
{
|
||||
if(len + pb->fill < audiobufsize)
|
||||
{
|
||||
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;
|
||||
}
|
||||
// Now, we at least got one full buffer to serve.
|
||||
|
||||
/* if we're too quick, let's wait */
|
||||
if(nobuffermode)
|
||||
{
|
||||
@@ -358,9 +401,24 @@ static int write_os2(out123_handle *ao,unsigned char *buf,int len)
|
||||
justflushed = FALSE;
|
||||
} else {
|
||||
nomoredata = FALSE;
|
||||
|
||||
memcpy(tobefilled->pBuffer, buf, len);
|
||||
tobefilled->ulBufferLength = len;
|
||||
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),
|
||||
@@ -370,8 +428,8 @@ static int write_os2(out123_handle *ao,unsigned char *buf,int len)
|
||||
|
||||
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,6 +723,7 @@ 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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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. */
|
||||
|
||||
81
src/local.c
81
src/local.c
@@ -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!
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
251
src/mpg123.c
251
src/mpg123.c
@@ -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, ¶m.output_device, 0},
|
||||
{'f', "scale", GLO_ARG | GLO_LONG, 0, ¶m.outscale, 0},
|
||||
{'n', "frames", GLO_ARG | GLO_LONG, 0, ¶m.frame_number, 0},
|
||||
#ifdef HAVE_TERMIOS
|
||||
{0, "no-visual", GLO_INT, 0, ¶m.term_visual, FALSE},
|
||||
{'C', "control", GLO_INT, 0, ¶m.term_ctrl, TRUE},
|
||||
{0, "no-control", GLO_INT, 0, ¶m.term_ctrl, FALSE},
|
||||
{0, "ctrlusr1", GLO_ARG | GLO_CHAR, 0, ¶m.term_usr1, 0},
|
||||
{0, "ctrlusr2", GLO_ARG | GLO_CHAR, 0, ¶m.term_usr2, 0},
|
||||
#endif
|
||||
#ifndef NOXFERMEM
|
||||
{'b', "buffer", GLO_ARG | GLO_LONG, 0, ¶m.usebuffer, 0},
|
||||
{0, "smooth", GLO_INT, 0, ¶m.smooth, 1},
|
||||
@@ -634,8 +674,12 @@ topt opts[] = {
|
||||
{0, "cpu", GLO_ARG | GLO_CHAR, 0, ¶m.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, ¶m.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 */
|
||||
if(filept) // total paranoia
|
||||
stream_close(filept);
|
||||
filept = stream_open(fname);
|
||||
if(!filept)
|
||||
return 0;
|
||||
|
||||
/* 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) )
|
||||
if( filept->htd.content_type.p != NULL
|
||||
&& !APPFLAG(MPG123APP_IGNORE_MIME) && !(debunk_mime(filept->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);
|
||||
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;
|
||||
}
|
||||
if(filept < 0)
|
||||
{
|
||||
error1("Access to http resource %s failed.", fname);
|
||||
|
||||
debug("OK... going to hook up libmpg123 and dump.");
|
||||
if(dump_setup(filept, mh))
|
||||
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(param.icy_interval > 0)
|
||||
{
|
||||
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));
|
||||
return 0;
|
||||
}
|
||||
debug("Track successfully opened.");
|
||||
|
||||
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,¶m);
|
||||
}
|
||||
#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
|
||||
|
||||
@@ -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
69
src/net123.h
Normal 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
306
src/net123_exec.c
Normal 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
262
src/net123_winhttp.c
Normal 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
227
src/net123_wininet.c
Normal 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);
|
||||
}
|
||||
11
src/out123.c
11
src/out123.c
@@ -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:
|
||||
|
||||
175
src/playlist.c
175
src/playlist.c
@@ -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)
|
||||
{
|
||||
firstline = 1; /* just opened */
|
||||
if(pl.file->fd == STDIN_FILENO)
|
||||
{
|
||||
pl.file = stdin;
|
||||
pl.stdin_used = TRUE;
|
||||
param.listname = NULL;
|
||||
pl.entry = 0;
|
||||
}
|
||||
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,96 +392,32 @@ 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);
|
||||
}
|
||||
httpdata_free(&htd);
|
||||
}
|
||||
if(fd < 0)
|
||||
{
|
||||
param.listname = NULL;
|
||||
stream_close(pl.file);
|
||||
pl.file = NULL;
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
pl.sockd = -1;
|
||||
#endif
|
||||
error("Invalid playlist from http_open()!\n");
|
||||
}
|
||||
else
|
||||
}
|
||||
}
|
||||
if(!pl.file)
|
||||
{
|
||||
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")))
|
||||
{
|
||||
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
|
||||
{
|
||||
/* have is the length of the string read, without the closing \0 */
|
||||
if(pl.linebuf.size <= have+1)
|
||||
{
|
||||
if(!mpg123_resize_string(&pl.linebuf, pl.linebuf.size+LINEBUF_STEP))
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -504,6 +425,7 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
|
||||
{
|
||||
if(!strcmp("[playlist]", pl.linebuf.p))
|
||||
{
|
||||
if(param.verbose)
|
||||
fprintf(stderr, "Note: detected Shoutcast/Winamp PLS playlist\n");
|
||||
pl.type = PLS;
|
||||
continue;
|
||||
@@ -542,7 +464,7 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
|
||||
}
|
||||
firstline = 0;
|
||||
}
|
||||
#if !defined(WIN32)
|
||||
#if !defined(WIN32)
|
||||
{
|
||||
size_t i;
|
||||
/* convert \ to / (from MS-like directory format) */
|
||||
@@ -551,9 +473,9 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
|
||||
if (pl.linebuf.p[i] == '\\') pl.linebuf.p[i] = '/';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (pl.linebuf.p[0]=='\0') continue; /* skip empty lines... */
|
||||
|
||||
#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 */
|
||||
@@ -614,6 +536,8 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
|
||||
&& (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)
|
||||
)
|
||||
{
|
||||
size_t need;
|
||||
@@ -645,21 +569,6 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (param.listname)
|
||||
if(pl.file) fclose (pl.file);
|
||||
param.listname = NULL;
|
||||
pl.file = NULL;
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
if( pl.sockd != -1)
|
||||
{
|
||||
win32_net_close(pl.sockd);
|
||||
pl.sockd = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
if(loptind < argc)
|
||||
{
|
||||
|
||||
@@ -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. */
|
||||
|
||||
394
src/streamdump.c
394
src/streamdump.c
@@ -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;
|
||||
|
||||
if(param.streamdump == NULL) return 0;
|
||||
|
||||
if(!param.quiet) fprintf(stderr, "Note: Dumping stream to %s\n", param.streamdump);
|
||||
int ret = MPG123_OK;
|
||||
int do_replace = 0; // full replacement with handle
|
||||
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
ret = mpg123_replace_reader(mh, dump_read, dump_seek);
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
|
||||
165
src/term.c
165
src/term.c
@@ -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,¶m);
|
||||
|
||||
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,¶m);
|
||||
// Assuming only changes happen via terminal control, these 3 values
|
||||
// are what counts.
|
||||
fprintf( stderr, "\n\nbass: %.3f\nmid: %.3f\ntreble: %.3f\n\n"
|
||||
, 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,¶m);
|
||||
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
|
||||
|
||||
|
||||
14
src/term.h
14
src/term.h
@@ -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
31
src/term_none.c
Normal 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
229
src/term_posix.c
Normal 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
113
src/term_win32.c
Normal 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
52
src/terms.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user