Built SDL2_image and _mixer static
This commit is contained in:
791
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/Makemodule.am
vendored
Normal file
791
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/Makemodule.am
vendored
Normal file
@@ -0,0 +1,791 @@
|
||||
# Module for non-recursive mpg123 build system.
|
||||
# Gah! Not even re-defining that variable is allowed in automake!
|
||||
# I WANT TO USE PROPER MAKE!
|
||||
# makedir := src/libout123/modules
|
||||
# Experiment: Does automake pick that up in a Make variable?
|
||||
# Damn, no! It complains wildly.
|
||||
# I just want to use GNU Make and be done with it!
|
||||
# Perhaps the next build system rewrite ...
|
||||
#makenam=src_libout123_modules
|
||||
|
||||
# Optionally containing the one static module to use.
|
||||
if !HAVE_MODULES
|
||||
noinst_LTLIBRARIES += src/libout123/modules/libdefaultmodule.la
|
||||
endif
|
||||
|
||||
# Do not include uneeded headers from mpg123app.h .
|
||||
libout123_mod_cppflags = -DBUILDING_OUTPUT_MODULES=1
|
||||
|
||||
# These are not tested and _very_ likely need work: aix alib hp os2 sgi mint
|
||||
|
||||
# Use that sh/perl script to generate the module entries:
|
||||
# Confused as to when to use _LIBADD and when _LDADD.
|
||||
# _LDADD gives errors from autotools.
|
||||
#echo \
|
||||
#dummy tinyalsa alsa qsa coreaudio esd jack nas oss portaudio \
|
||||
#pulse sdl sndio sun win32 win32_wasapi aix alib arts hp os2 \
|
||||
#sgi mint openal \
|
||||
#| tr ' ' '\n' |
|
||||
#perl -ne 'chomp; $big = uc($_); print <<EOT;
|
||||
#
|
||||
#if HAVE_MODULES
|
||||
#if HAVE_$big
|
||||
#pkglib_LTLIBRARIES += \src/libout123/modules/output_$_.la
|
||||
#src_libout123_modules_output_${_}_la_SOURCES = \\
|
||||
# src/libout123/modules/$_.c
|
||||
#src_libout123_modules_output_${_}_la_LDFLAGS = \\
|
||||
# -module -no-undefined -avoid-version \\
|
||||
# -export-dynamic -export-symbols-regex '"'"'^mpg123_'"'"' \\
|
||||
# \@${big}_LDFLAGS\@
|
||||
#src_libout123_modules_output_${_}_la_CFLAGS = \@${big}_CFLAGS\@
|
||||
#src_libout123_modules_output_${_}_la_LIBADD = \\
|
||||
# src/compat/libcompat_str.la \\
|
||||
# \@${big}_LIBS\@
|
||||
#src_libout123_modules_outout_${_}_la_CPPFLAGS = \\
|
||||
# \$(AM_CPPFLAGS) \\
|
||||
# \$(libout123_mod_cppflags)
|
||||
#endif
|
||||
#else
|
||||
#if BUILD_$big
|
||||
#src_libout123_modules_libdefaultmodule_la_SOURCES = \\
|
||||
# src/libout123/modules/$_.c
|
||||
#src_libout123_modules_libdefaultmodule_la_CFLAGS = \@${big}_CFLAGS\@
|
||||
#src_libout123_modules_libdefaultmodule_la_LDFLAGS = \@${big}_LDFLAGS\@
|
||||
#src_libout123_modules_libdefaultmodule_la_LIBADD = \@${big}_LIBS\@
|
||||
#src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \\
|
||||
# \$(AM_CPPFLAGS) \\
|
||||
# \$(libout123_mod_cppflags)
|
||||
#endif
|
||||
#endif
|
||||
#EOT
|
||||
#'
|
||||
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_DUMMY
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_dummy.la
|
||||
src_libout123_modules_output_dummy_la_SOURCES = \
|
||||
src/libout123/modules/dummy.c
|
||||
src_libout123_modules_output_dummy_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@DUMMY_LDFLAGS@
|
||||
src_libout123_modules_output_dummy_la_CFLAGS = @DUMMY_CFLAGS@
|
||||
src_libout123_modules_output_dummy_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@DUMMY_LIBS@
|
||||
src_libout123_modules_outout_dummy_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_DUMMY
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/dummy.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @DUMMY_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @DUMMY_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @DUMMY_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_TINYALSA
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_tinyalsa.la
|
||||
src_libout123_modules_output_tinyalsa_la_SOURCES = \
|
||||
src/libout123/modules/tinyalsa.c
|
||||
src_libout123_modules_output_tinyalsa_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@TINYALSA_LDFLAGS@
|
||||
src_libout123_modules_output_tinyalsa_la_CFLAGS = @TINYALSA_CFLAGS@
|
||||
src_libout123_modules_output_tinyalsa_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@TINYALSA_LIBS@
|
||||
src_libout123_modules_outout_tinyalsa_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_TINYALSA
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/tinyalsa.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @TINYALSA_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @TINYALSA_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @TINYALSA_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_ALSA
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_alsa.la
|
||||
src_libout123_modules_output_alsa_la_SOURCES = \
|
||||
src/libout123/modules/alsa.c
|
||||
src_libout123_modules_output_alsa_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@ALSA_LDFLAGS@
|
||||
src_libout123_modules_output_alsa_la_CFLAGS = @ALSA_CFLAGS@
|
||||
src_libout123_modules_output_alsa_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@ALSA_LIBS@
|
||||
src_libout123_modules_outout_alsa_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_ALSA
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/alsa.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @ALSA_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @ALSA_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @ALSA_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_QSA
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_qsa.la
|
||||
src_libout123_modules_output_qsa_la_SOURCES = \
|
||||
src/libout123/modules/qsa.c
|
||||
src_libout123_modules_output_qsa_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@QSA_LDFLAGS@
|
||||
src_libout123_modules_output_qsa_la_CFLAGS = @QSA_CFLAGS@
|
||||
src_libout123_modules_output_qsa_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@QSA_LIBS@
|
||||
src_libout123_modules_outout_qsa_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_QSA
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/qsa.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @QSA_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @QSA_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @QSA_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_COREAUDIO
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_coreaudio.la
|
||||
src_libout123_modules_output_coreaudio_la_SOURCES = \
|
||||
src/libout123/modules/coreaudio.c
|
||||
src_libout123_modules_output_coreaudio_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@COREAUDIO_LDFLAGS@
|
||||
src_libout123_modules_output_coreaudio_la_CFLAGS = @COREAUDIO_CFLAGS@
|
||||
src_libout123_modules_output_coreaudio_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@COREAUDIO_LIBS@
|
||||
src_libout123_modules_outout_coreaudio_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_COREAUDIO
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/coreaudio.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @COREAUDIO_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @COREAUDIO_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @COREAUDIO_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_ESD
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_esd.la
|
||||
src_libout123_modules_output_esd_la_SOURCES = \
|
||||
src/libout123/modules/esd.c
|
||||
src_libout123_modules_output_esd_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@ESD_LDFLAGS@
|
||||
src_libout123_modules_output_esd_la_CFLAGS = @ESD_CFLAGS@
|
||||
src_libout123_modules_output_esd_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@ESD_LIBS@
|
||||
src_libout123_modules_outout_esd_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_ESD
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/esd.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @ESD_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @ESD_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @ESD_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_JACK
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_jack.la
|
||||
src_libout123_modules_output_jack_la_SOURCES = \
|
||||
src/libout123/modules/jack.c
|
||||
src_libout123_modules_output_jack_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@JACK_LDFLAGS@
|
||||
src_libout123_modules_output_jack_la_CFLAGS = @JACK_CFLAGS@
|
||||
src_libout123_modules_output_jack_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@JACK_LIBS@
|
||||
src_libout123_modules_outout_jack_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_JACK
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/jack.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @JACK_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @JACK_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @JACK_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_NAS
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_nas.la
|
||||
src_libout123_modules_output_nas_la_SOURCES = \
|
||||
src/libout123/modules/nas.c
|
||||
src_libout123_modules_output_nas_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@NAS_LDFLAGS@
|
||||
src_libout123_modules_output_nas_la_CFLAGS = @NAS_CFLAGS@
|
||||
src_libout123_modules_output_nas_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@NAS_LIBS@
|
||||
src_libout123_modules_outout_nas_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_NAS
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/nas.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @NAS_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @NAS_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @NAS_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_OSS
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_oss.la
|
||||
src_libout123_modules_output_oss_la_SOURCES = \
|
||||
src/libout123/modules/oss.c
|
||||
src_libout123_modules_output_oss_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@OSS_LDFLAGS@
|
||||
src_libout123_modules_output_oss_la_CFLAGS = @OSS_CFLAGS@
|
||||
src_libout123_modules_output_oss_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@OSS_LIBS@
|
||||
src_libout123_modules_outout_oss_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_OSS
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/oss.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @OSS_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @OSS_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @OSS_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_PORTAUDIO
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_portaudio.la
|
||||
src_libout123_modules_output_portaudio_la_SOURCES = \
|
||||
src/libout123/modules/portaudio.c
|
||||
src_libout123_modules_output_portaudio_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@PORTAUDIO_LDFLAGS@
|
||||
src_libout123_modules_output_portaudio_la_CFLAGS = @PORTAUDIO_CFLAGS@
|
||||
src_libout123_modules_output_portaudio_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@PORTAUDIO_LIBS@
|
||||
src_libout123_modules_outout_portaudio_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_PORTAUDIO
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/portaudio.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @PORTAUDIO_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @PORTAUDIO_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @PORTAUDIO_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_PULSE
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_pulse.la
|
||||
src_libout123_modules_output_pulse_la_SOURCES = \
|
||||
src/libout123/modules/pulse.c
|
||||
src_libout123_modules_output_pulse_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@PULSE_LDFLAGS@
|
||||
src_libout123_modules_output_pulse_la_CFLAGS = @PULSE_CFLAGS@
|
||||
src_libout123_modules_output_pulse_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@PULSE_LIBS@
|
||||
src_libout123_modules_outout_pulse_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_PULSE
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/pulse.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @PULSE_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @PULSE_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @PULSE_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_SDL
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_sdl.la
|
||||
src_libout123_modules_output_sdl_la_SOURCES = \
|
||||
src/libout123/modules/sdl.c
|
||||
src_libout123_modules_output_sdl_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@SDL_LDFLAGS@
|
||||
src_libout123_modules_output_sdl_la_CFLAGS = @SDL_CFLAGS@
|
||||
src_libout123_modules_output_sdl_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@SDL_LIBS@
|
||||
src_libout123_modules_outout_sdl_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_SDL
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/sdl.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @SDL_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @SDL_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @SDL_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_SNDIO
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_sndio.la
|
||||
src_libout123_modules_output_sndio_la_SOURCES = \
|
||||
src/libout123/modules/sndio.c
|
||||
src_libout123_modules_output_sndio_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@SNDIO_LDFLAGS@
|
||||
src_libout123_modules_output_sndio_la_CFLAGS = @SNDIO_CFLAGS@
|
||||
src_libout123_modules_output_sndio_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@SNDIO_LIBS@
|
||||
src_libout123_modules_outout_sndio_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_SNDIO
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/sndio.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @SNDIO_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @SNDIO_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @SNDIO_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_SUN
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_sun.la
|
||||
src_libout123_modules_output_sun_la_SOURCES = \
|
||||
src/libout123/modules/sun.c
|
||||
src_libout123_modules_output_sun_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@SUN_LDFLAGS@
|
||||
src_libout123_modules_output_sun_la_CFLAGS = @SUN_CFLAGS@
|
||||
src_libout123_modules_output_sun_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@SUN_LIBS@
|
||||
src_libout123_modules_outout_sun_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_SUN
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/sun.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @SUN_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @SUN_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @SUN_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_WIN32
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_win32.la
|
||||
src_libout123_modules_output_win32_la_SOURCES = \
|
||||
src/libout123/modules/win32.c
|
||||
src_libout123_modules_output_win32_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@WIN32_LDFLAGS@
|
||||
src_libout123_modules_output_win32_la_CFLAGS = @WIN32_CFLAGS@
|
||||
src_libout123_modules_output_win32_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@WIN32_LIBS@
|
||||
src_libout123_modules_outout_win32_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_WIN32
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/win32.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @WIN32_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @WIN32_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @WIN32_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_WIN32_WASAPI
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_win32_wasapi.la
|
||||
src_libout123_modules_output_win32_wasapi_la_SOURCES = \
|
||||
src/libout123/modules/win32_wasapi.c
|
||||
src_libout123_modules_output_win32_wasapi_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@WIN32_WASAPI_LDFLAGS@
|
||||
src_libout123_modules_output_win32_wasapi_la_CFLAGS = @WIN32_WASAPI_CFLAGS@
|
||||
src_libout123_modules_output_win32_wasapi_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@WIN32_WASAPI_LIBS@
|
||||
src_libout123_modules_outout_win32_wasapi_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_WIN32_WASAPI
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/win32_wasapi.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @WIN32_WASAPI_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @WIN32_WASAPI_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @WIN32_WASAPI_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_AIX
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_aix.la
|
||||
src_libout123_modules_output_aix_la_SOURCES = \
|
||||
src/libout123/modules/aix.c
|
||||
src_libout123_modules_output_aix_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@AIX_LDFLAGS@
|
||||
src_libout123_modules_output_aix_la_CFLAGS = @AIX_CFLAGS@
|
||||
src_libout123_modules_output_aix_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@AIX_LIBS@
|
||||
src_libout123_modules_outout_aix_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_AIX
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/aix.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @AIX_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @AIX_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @AIX_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_ALIB
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_alib.la
|
||||
src_libout123_modules_output_alib_la_SOURCES = \
|
||||
src/libout123/modules/alib.c
|
||||
src_libout123_modules_output_alib_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@ALIB_LDFLAGS@
|
||||
src_libout123_modules_output_alib_la_CFLAGS = @ALIB_CFLAGS@
|
||||
src_libout123_modules_output_alib_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@ALIB_LIBS@
|
||||
src_libout123_modules_outout_alib_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_ALIB
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/alib.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @ALIB_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @ALIB_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @ALIB_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_ARTS
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_arts.la
|
||||
src_libout123_modules_output_arts_la_SOURCES = \
|
||||
src/libout123/modules/arts.c
|
||||
src_libout123_modules_output_arts_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@ARTS_LDFLAGS@
|
||||
src_libout123_modules_output_arts_la_CFLAGS = @ARTS_CFLAGS@
|
||||
src_libout123_modules_output_arts_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@ARTS_LIBS@
|
||||
src_libout123_modules_outout_arts_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_ARTS
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/arts.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @ARTS_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @ARTS_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @ARTS_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_HP
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_hp.la
|
||||
src_libout123_modules_output_hp_la_SOURCES = \
|
||||
src/libout123/modules/hp.c
|
||||
src_libout123_modules_output_hp_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@HP_LDFLAGS@
|
||||
src_libout123_modules_output_hp_la_CFLAGS = @HP_CFLAGS@
|
||||
src_libout123_modules_output_hp_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@HP_LIBS@
|
||||
src_libout123_modules_outout_hp_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_HP
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/hp.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @HP_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @HP_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @HP_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_OS2
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_os2.la
|
||||
src_libout123_modules_output_os2_la_SOURCES = \
|
||||
src/libout123/modules/os2.c
|
||||
src_libout123_modules_output_os2_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@OS2_LDFLAGS@
|
||||
src_libout123_modules_output_os2_la_CFLAGS = @OS2_CFLAGS@
|
||||
src_libout123_modules_output_os2_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@OS2_LIBS@
|
||||
src_libout123_modules_outout_os2_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_OS2
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/os2.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @OS2_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @OS2_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @OS2_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_SGI
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_sgi.la
|
||||
src_libout123_modules_output_sgi_la_SOURCES = \
|
||||
src/libout123/modules/sgi.c
|
||||
src_libout123_modules_output_sgi_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@SGI_LDFLAGS@
|
||||
src_libout123_modules_output_sgi_la_CFLAGS = @SGI_CFLAGS@
|
||||
src_libout123_modules_output_sgi_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@SGI_LIBS@
|
||||
src_libout123_modules_outout_sgi_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_SGI
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/sgi.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @SGI_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @SGI_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @SGI_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_MINT
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_mint.la
|
||||
src_libout123_modules_output_mint_la_SOURCES = \
|
||||
src/libout123/modules/mint.c
|
||||
src_libout123_modules_output_mint_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@MINT_LDFLAGS@
|
||||
src_libout123_modules_output_mint_la_CFLAGS = @MINT_CFLAGS@
|
||||
src_libout123_modules_output_mint_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@MINT_LIBS@
|
||||
src_libout123_modules_outout_mint_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_MINT
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/mint.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @MINT_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @MINT_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @MINT_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_OPENAL
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_openal.la
|
||||
src_libout123_modules_output_openal_la_SOURCES = \
|
||||
src/libout123/modules/openal.c
|
||||
src_libout123_modules_output_openal_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@OPENAL_LDFLAGS@
|
||||
src_libout123_modules_output_openal_la_CFLAGS = @OPENAL_CFLAGS@
|
||||
src_libout123_modules_output_openal_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@OPENAL_LIBS@
|
||||
src_libout123_modules_outout_openal_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_OPENAL
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/openal.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @OPENAL_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @OPENAL_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @OPENAL_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
# Get rid of .la files, at least _after_ install.
|
||||
install-exec-hook:
|
||||
cd $(DESTDIR)$(pkglibdir) && rm -f @output_modules_la@
|
||||
# The above breaks uninstall of module .so files?
|
||||
uninstall-hook:
|
||||
for m in @output_modules_la@; do eval $$(grep dlname= src/libout123/modules/$$m) && rm -f $(DESTDIR)$(pkglibdir)/$$dlname; done
|
||||
endif
|
||||
304
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/aix.c
vendored
Normal file
304
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/aix.c
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
aix: Driver for IBM RS/6000 with AIX Ultimedia Services
|
||||
|
||||
copyright ?-2016 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 Juergen Schoew and Tomas Oegren
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/audio.h>
|
||||
#include <stropts.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* use AUDIO_BSIZE to set the msec for audio buffering in Ultimedia library
|
||||
*/
|
||||
/* #define AUDIO_BSIZE AUDIO_IGNORE */
|
||||
#define AUDIO_BSIZE ( ao->device_buffer > 0. \
|
||||
? (long)(ao->device_buffer*1000) \
|
||||
: 200 )
|
||||
|
||||
static int rate_best_match(out123_handle *ao)
|
||||
{
|
||||
static long valid [ ] = { 5510, 6620, 8000, 9600, 11025, 16000, 18900,
|
||||
22050, 27420, 32000, 33075, 37800, 44100, 48000, 0 };
|
||||
int i = 0;
|
||||
long best = 8000;
|
||||
|
||||
if(!ao || ao->fn < 0 || ao->rate < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (valid [i]) {
|
||||
if (abs(valid[i] - ao->rate) < abs(best - ao->rate))
|
||||
{
|
||||
best = valid [i];
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
ao->rate = best;
|
||||
return best;
|
||||
}
|
||||
|
||||
static int reset_parameters(out123_handle *ao)
|
||||
{
|
||||
audio_control acontrol;
|
||||
audio_change achange;
|
||||
audio_init ainit;
|
||||
int ret;
|
||||
|
||||
memset ( & achange, '\0', sizeof (achange));
|
||||
memset ( & acontrol, '\0', sizeof (acontrol));
|
||||
|
||||
achange.balance = 0x3fff0000;
|
||||
achange.balance_delay = 0;
|
||||
achange.volume = (long) (0x7fff << 16);
|
||||
achange.volume_delay = 0;
|
||||
achange.input = AUDIO_IGNORE;
|
||||
if (ao->flags == -1) achange.output = INTERNAL_SPEAKER;
|
||||
else achange.output = 0;
|
||||
|
||||
if(ao->flags & OUT123_INTERNAL_SPEAKER)
|
||||
achange.output |= INTERNAL_SPEAKER;
|
||||
if(ao->flags & OUT123_HEADPHONES)
|
||||
achange.output |= EXTERNAL_SPEAKER;
|
||||
if(ao->flags & OUT123_LINE_OUT)
|
||||
achange.output |= OUTPUT_1;
|
||||
if(ao->flags == 0)
|
||||
achange.output = AUDIO_IGNORE;
|
||||
|
||||
achange.treble = AUDIO_IGNORE;
|
||||
achange.bass = AUDIO_IGNORE;
|
||||
achange.pitch = AUDIO_IGNORE;
|
||||
achange.monitor = AUDIO_IGNORE;
|
||||
achange.dev_info = (char *) NULL;
|
||||
|
||||
acontrol.ioctl_request = AUDIO_CHANGE;
|
||||
acontrol.position = 0;
|
||||
acontrol.request_info = (char *) & achange;
|
||||
|
||||
ret = ioctl (ao->fn, AUDIO_CONTROL, & acontrol);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Init Device for new values */
|
||||
if (ao->rate >0) {
|
||||
memset ( & ainit, '\0', sizeof (ainit));
|
||||
ainit.srate = rate_best_match(ao);
|
||||
if (ao->channels > 0)
|
||||
ainit.channels = ao->channels;
|
||||
else
|
||||
ainit.channels = 1;
|
||||
switch (ao->format) {
|
||||
default :
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 16;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_16:
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 16;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT | SIGNED;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT | SIGNED;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
ainit.mode = MU_LAW;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
ainit.mode = A_LAW;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
}
|
||||
ainit.operation = PLAY;
|
||||
ainit.bsize = AUDIO_BSIZE;
|
||||
|
||||
ret = ioctl (ao->fn, AUDIO_INIT, & ainit);
|
||||
if (ret < 0) {
|
||||
error("Can't set new audio parameters!");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
acontrol.ioctl_request = AUDIO_START;
|
||||
acontrol.request_info = NULL;
|
||||
acontrol.position = 0;
|
||||
|
||||
ret = ioctl (ao->fn, AUDIO_CONTROL, & acontrol);
|
||||
if (ret < 0) {
|
||||
error("Can't reset audio!");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_aix(out123_handle *ao)
|
||||
{
|
||||
audio_init ainit;
|
||||
int ret;
|
||||
const char *dev = ao->device;
|
||||
|
||||
if(!dev) {
|
||||
if(getenv("AUDIODEV")) {
|
||||
dev = getenv("AUDIODEV");
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
} else {
|
||||
dev = "/dev/paud0/1"; /* paud0 for PCI */
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
if ((ao->fn == -1) & (errno == ENOENT)) {
|
||||
dev = "/dev/baud0/1"; /* baud0 for MCA */
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
}
|
||||
}
|
||||
} else ao->fn = open(dev,O_WRONLY);
|
||||
|
||||
if(ao->fn < 0) {
|
||||
error("Can't open audio device!");
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
/* Init to default values */
|
||||
memset ( & ainit, '\0', sizeof (ainit));
|
||||
ainit.srate = 44100;
|
||||
ainit.channels = 2;
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 16;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
ainit.operation = PLAY;
|
||||
ainit.bsize = AUDIO_BSIZE;
|
||||
|
||||
ret = ioctl (ao->fn, AUDIO_INIT, & ainit);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
reset_parameters(ao);
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int get_formats_aix(out123_handle *ao)
|
||||
{
|
||||
/* ULTIMEDIA DOCUMENTATION SAYS:
|
||||
The Ultimedia Audio Adapter supports fourteen sample rates you can use to
|
||||
capture and playback audio data. The rates are (in kHz): 5.51, 6.62, 8.0,
|
||||
9.6, 11.025, 16.0, 18.9, 22.050, 27.42, 32.0, 33.075, 37.8, 44.1, and 48.0.
|
||||
These rates are supported for mono and stereo PCM (8- and 16-bit), mu-law,
|
||||
and A-law.
|
||||
*/
|
||||
|
||||
long rate;
|
||||
|
||||
rate = ao->rate;
|
||||
rate_best_match(ao);
|
||||
if (ao->rate == rate)
|
||||
return (MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_16|
|
||||
MPG123_ENC_UNSIGNED_8|MPG123_ENC_SIGNED_8|
|
||||
MPG123_ENC_ULAW_8|MPG123_ENC_ALAW_8);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_aix(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_aix(out123_handle *ao)
|
||||
{
|
||||
audio_control acontrol;
|
||||
audio_buffer abuffer;
|
||||
int ret,i;
|
||||
|
||||
/* Don't close the audio-device until it's played all its contents */
|
||||
memset ( & acontrol, '\0', sizeof ( acontrol ) );
|
||||
acontrol.request_info = &abuffer;
|
||||
acontrol.position = 0;
|
||||
i=50; /* Don't do this forever on a bad day :-) */
|
||||
|
||||
while (i-- > 0) {
|
||||
if ((ioctl(ao->fn, AUDIO_BUFFER, &acontrol))< 0) {
|
||||
error1("buffer read failed: %d", errno);
|
||||
break;
|
||||
} else {
|
||||
if (abuffer.flags <= 0) break;
|
||||
}
|
||||
usleep(200000); /* sleep 0.2 sec */
|
||||
}
|
||||
|
||||
memset ( & acontrol, '\0', sizeof ( acontrol ) );
|
||||
acontrol.ioctl_request = AUDIO_STOP;
|
||||
acontrol.request_info = NULL;
|
||||
acontrol.position = 0;
|
||||
|
||||
ret = ioctl ( ao->fn, AUDIO_CONTROL, & acontrol );
|
||||
if (ret < 0) error("Can't close audio!");
|
||||
|
||||
ret = close (ao->fn);
|
||||
if (ret < 0) error("Can't close audio!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_aix(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
static int init_aix(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_aix;
|
||||
ao->flush = flush_aix;
|
||||
ao->write = write_aix;
|
||||
ao->get_formats = get_formats_aix;
|
||||
ao->close = close_aix;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "aix",
|
||||
/* description */ "Output audio on IBM RS/6000 with AIX Ultimedia Services.",
|
||||
/* revision */ "$Rev: 932 $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_aix,
|
||||
};
|
||||
|
||||
209
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/alib.c
vendored
Normal file
209
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/alib.c
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
alib: audio output for HP-UX using alib
|
||||
|
||||
copyright ?-2006 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 Erwan Ducroquet
|
||||
based on source code from HP (Audio SDK)
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* for mpg123 :
|
||||
* hpux:
|
||||
* $(MAKE) \
|
||||
* CC=cc \
|
||||
* LDFLAGS=-L/opt/audio/lib \
|
||||
* AUDIO_LIB=-lAlib \
|
||||
* OBJECTS=decode.o dct64.o \
|
||||
* CFLAGS=-Ae +O3 -DREAL_IS_FLOAT -D_HPUX_SOURCE -DHPUX -I/opt/audio/include \
|
||||
* mpg123
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* For the user :
|
||||
* If you launch mpg123 on a XTerm with sound capabilities, it's OK
|
||||
* Else, you have to set the environment variable "AUDIO" to the name of
|
||||
* an HP Xterm with sound card.
|
||||
*/
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include <Alib.h> /* /opt/audio/include */
|
||||
#include <CUlib.h> /* /opt/audio/include */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/* FIXME: These globals should be moved into a structure */
|
||||
static Audio *audioServer = (Audio *) NULL;
|
||||
static struct protoent *tcpProtocolEntry;
|
||||
static ATransID xid;
|
||||
|
||||
static void printAudioError(Audio *audio,char *message,int errorCode) {
|
||||
char errorbuff[132];
|
||||
AGetErrorText(audio, errorCode, errorbuff, 131);
|
||||
error2("%s: %s", message, errorbuff);
|
||||
}
|
||||
static long myHandler(Audio *audio,AErrorEvent *err_event) {
|
||||
printAudioError( audio, "Audio error", err_event->error_code );
|
||||
/* we cannot just do random exists, that messes terminal up
|
||||
need proper error propagation in that case for future, setting intflag or such */
|
||||
/* exit(1); */
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/*
|
||||
* Set the fn element of ai
|
||||
* Use ao->rate and ao->channels
|
||||
* Doesn't set any volume
|
||||
*/
|
||||
|
||||
/* return on error leaves stuff dirty here... */
|
||||
static int open_alib(out123_handle *ao)
|
||||
{
|
||||
AudioAttributes Attribs;
|
||||
AudioAttrMask AttribsMask;
|
||||
AGainEntry gainEntry[4];
|
||||
SSPlayParams playParams;
|
||||
SStream audioStream;
|
||||
AErrorHandler prevHandler;
|
||||
char server[1];
|
||||
int i;
|
||||
long status;
|
||||
|
||||
if (audioServer) {
|
||||
error("openAudio: audio already open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
prevHandler = ASetErrorHandler(myHandler);
|
||||
|
||||
server[0] = '\0';
|
||||
audioServer = AOpenAudio( server, NULL );
|
||||
if (audioServer==NULL) {
|
||||
error("Error: could not open audio\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ao->fn = socket( AF_INET, SOCK_STREAM, 0 );
|
||||
if(ao->fn<0) {
|
||||
error("Socket creation failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Attribs.type = ATSampled;
|
||||
Attribs.attr.sampled_attr.sampling_rate = ao->rate;
|
||||
Attribs.attr.sampled_attr.channels = ao->channels;
|
||||
Attribs.attr.sampled_attr.data_format = ADFLin16;
|
||||
AttribsMask = ASSamplingRateMask | ASChannelsMask | ASDataFormatMask;
|
||||
|
||||
gainEntry[0].gain = AUnityGain;
|
||||
gainEntry[0].u.o.out_ch = AOCTMono;
|
||||
gainEntry[0].u.o.out_dst = AODTDefaultOutput;
|
||||
|
||||
playParams.gain_matrix.type = AGMTOutput; /* gain matrix */
|
||||
playParams.gain_matrix.num_entries = 1;
|
||||
playParams.gain_matrix.gain_entries = gainEntry;
|
||||
playParams.play_volume = AUnityGain; /* play volume */
|
||||
playParams.priority = APriorityNormal; /* normal priority */
|
||||
playParams.event_mask = 0; /* don't solicit any events */
|
||||
|
||||
xid=APlaySStream(audioServer,AttribsMask,&Attribs,
|
||||
&playParams,&audioStream,NULL);
|
||||
|
||||
status=connect(ao->fn,
|
||||
(struct sockaddr *) &audioStream.tcp_sockaddr,
|
||||
sizeof(struct sockaddr_in) );
|
||||
if (status<0) {
|
||||
error("Connect failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
i=-1;
|
||||
tcpProtocolEntry=getprotobyname("tcp");
|
||||
setsockopt(ao->fn,tcpProtocolEntry->p_proto,TCP_NODELAY,&i,sizeof(i));
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static int close_alib(out123_handle *ao)
|
||||
{
|
||||
close(ao->fn);
|
||||
ASetCloseDownMode( audioServer, AKeepTransactions, NULL );
|
||||
ACloseAudio( audioServer, NULL );
|
||||
audioServer = (Audio *) NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/*
|
||||
* very simple
|
||||
* deserv to be inline
|
||||
*/
|
||||
|
||||
static int write_alib(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len*2);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static int get_formats_alib(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
static void flush_alib(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int init_alib(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_alib;
|
||||
ao->flush = flush_alib;
|
||||
ao->write = write_alib;
|
||||
ao->get_formats = get_formats_alib;
|
||||
ao->close = close_alib;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "alib",
|
||||
/* description */ "Output audio HP-UX using alib.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_alib,
|
||||
};
|
||||
|
||||
309
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/alsa.c
vendored
Normal file
309
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/alsa.c
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
alsa: sound output with Advanced Linux Sound Architecture 1.x API
|
||||
|
||||
copyright 2006-2016 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 Clemens Ladisch <clemens@ladisch.de>
|
||||
*/
|
||||
|
||||
/* ALSA headers define struct timeval if no POSIX macro is set,
|
||||
nicely in conflict with definitions in system headers. They had
|
||||
a discussion about that a long time ago:
|
||||
http://mailman.alsa-project.org/pipermail/alsa-devel/2007-June/001684.html
|
||||
... seems like the conclusion was not carried through.
|
||||
*/
|
||||
#define _POSIX_SOURCE
|
||||
/* Things are still missing if _DEFAULT_SOURCE is not defined (for recent
|
||||
glibc, I presume. */
|
||||
#define _DEFAULT_SOURCE
|
||||
#include "out123_int.h"
|
||||
#include <errno.h>
|
||||
|
||||
/* make ALSA 0.9.x compatible to the 1.0.x API */
|
||||
#define ALSA_PCM_NEW_HW_PARAMS_API
|
||||
#define ALSA_PCM_NEW_SW_PARAMS_API
|
||||
|
||||
#include <alloca.h> /* GCC complains about missing declaration of alloca. */
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* Total buffer size in seconds, 0.2 is more true to what ALSA maximally uses
|
||||
here (8192 samples). The earlier default of 0.5 was never true. */
|
||||
#define BUFFER_LENGTH (ao->device_buffer > 0. ? ao->device_buffer : 0.2)
|
||||
|
||||
static const struct {
|
||||
snd_pcm_format_t alsa;
|
||||
int mpg123;
|
||||
} format_map[] = {
|
||||
{ SND_PCM_FORMAT_S16, MPG123_ENC_SIGNED_16 },
|
||||
{ SND_PCM_FORMAT_U16, MPG123_ENC_UNSIGNED_16 },
|
||||
{ SND_PCM_FORMAT_U8, MPG123_ENC_UNSIGNED_8 },
|
||||
{ SND_PCM_FORMAT_S8, MPG123_ENC_SIGNED_8 },
|
||||
{ SND_PCM_FORMAT_A_LAW, MPG123_ENC_ALAW_8 },
|
||||
{ SND_PCM_FORMAT_MU_LAW, MPG123_ENC_ULAW_8 },
|
||||
{ SND_PCM_FORMAT_S32, MPG123_ENC_SIGNED_32 },
|
||||
{ SND_PCM_FORMAT_U32, MPG123_ENC_UNSIGNED_32 },
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
{ SND_PCM_FORMAT_S24_3BE, MPG123_ENC_SIGNED_24 },
|
||||
{ SND_PCM_FORMAT_U24_3BE, MPG123_ENC_UNSIGNED_24 },
|
||||
#else
|
||||
{ SND_PCM_FORMAT_S24_3LE, MPG123_ENC_SIGNED_24 },
|
||||
{ SND_PCM_FORMAT_U24_3LE, MPG123_ENC_UNSIGNED_24 },
|
||||
#endif
|
||||
{ SND_PCM_FORMAT_FLOAT, MPG123_ENC_FLOAT_32 },
|
||||
{ SND_PCM_FORMAT_FLOAT64, MPG123_ENC_FLOAT_64 }
|
||||
};
|
||||
#define NUM_FORMATS (sizeof format_map / sizeof format_map[0])
|
||||
|
||||
|
||||
static int rates_match(long int desired, unsigned int actual)
|
||||
{
|
||||
return actual * 100 > desired * (100 - AUDIO_RATE_TOLERANCE) &&
|
||||
actual * 100 < desired * (100 + AUDIO_RATE_TOLERANCE);
|
||||
}
|
||||
|
||||
static int initialize_device(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_hw_params_t *hw=NULL;
|
||||
snd_pcm_sw_params_t *sw=NULL;
|
||||
snd_pcm_uframes_t buffer_size;
|
||||
snd_pcm_uframes_t period_size;
|
||||
snd_pcm_format_t format;
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
unsigned int rate;
|
||||
int i;
|
||||
|
||||
snd_pcm_hw_params_alloca(&hw); /* Ignore GCC warning here... alsa-lib>=1.0.16 doesn't trigger that anymore, too. */
|
||||
if (snd_pcm_hw_params_any(pcm, hw) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): no configuration available");
|
||||
return -1;
|
||||
}
|
||||
if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): device does not support interleaved access");
|
||||
return -1;
|
||||
}
|
||||
format = SND_PCM_FORMAT_UNKNOWN;
|
||||
for (i = 0; i < NUM_FORMATS; ++i) {
|
||||
if (ao->format == format_map[i].mpg123) {
|
||||
format = format_map[i].alsa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (format == SND_PCM_FORMAT_UNKNOWN) {
|
||||
if(!AOQUIET) error1("initialize_device(): invalid sample format %d", ao->format);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (snd_pcm_hw_params_set_format(pcm, hw, format) < 0) {
|
||||
if(!AOQUIET) error1("initialize_device(): cannot set format %s", snd_pcm_format_name(format));
|
||||
return -1;
|
||||
}
|
||||
if (snd_pcm_hw_params_set_channels(pcm, hw, ao->channels) < 0) {
|
||||
if(!AOQUIET) error1("initialize_device(): cannot set %d channels", ao->channels);
|
||||
return -1;
|
||||
}
|
||||
rate = ao->rate;
|
||||
if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, NULL) < 0) {
|
||||
if(!AOQUIET) error1("initialize_device(): cannot set rate %u", rate);
|
||||
return -1;
|
||||
}
|
||||
if (!rates_match(ao->rate, rate)) {
|
||||
if(!AOQUIET) error2("initialize_device(): rate %ld not available, using %u", ao->rate, rate);
|
||||
/* return -1; */
|
||||
}
|
||||
buffer_size = rate * BUFFER_LENGTH;
|
||||
if (snd_pcm_hw_params_set_buffer_size_near(pcm, hw, &buffer_size) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set buffer size");
|
||||
return -1;
|
||||
}
|
||||
debug1("buffer_size=%lu", (unsigned long)buffer_size);
|
||||
period_size = buffer_size / 3; /* 3 periods is so much more common. */
|
||||
if (snd_pcm_hw_params_set_period_size_near(pcm, hw, &period_size, NULL) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set period size");
|
||||
return -1;
|
||||
}
|
||||
debug1("period_size=%lu", (unsigned long)period_size);
|
||||
if (snd_pcm_hw_params(pcm, hw) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set hw params");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snd_pcm_sw_params_alloca(&sw);
|
||||
if (snd_pcm_sw_params_current(pcm, sw) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot get sw params");
|
||||
return -1;
|
||||
}
|
||||
/* start playing right away */
|
||||
if (snd_pcm_sw_params_set_start_threshold(pcm, sw, 1) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set start threshold");
|
||||
return -1;
|
||||
}
|
||||
/* wake up on every interrupt */
|
||||
if (snd_pcm_sw_params_set_avail_min(pcm, sw, 1) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set min available");
|
||||
return -1;
|
||||
}
|
||||
#if SND_LIB_VERSION < ((1<<16)|16)
|
||||
/* Always write as many frames as possible (deprecated since alsa-lib 1.0.16) */
|
||||
if (snd_pcm_sw_params_set_xfer_align(pcm, sw, 1) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set transfer alignment");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (snd_pcm_sw_params(pcm, sw) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set sw params");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
static void error_ignorer(const char *file, int line, const char *function, int err, const char *fmt,...)
|
||||
{
|
||||
/* I can make ALSA silent. */
|
||||
}
|
||||
#endif
|
||||
|
||||
static int open_alsa(out123_handle *ao)
|
||||
{
|
||||
const char *pcm_name;
|
||||
snd_pcm_t *pcm=NULL;
|
||||
debug1("open_alsa with %p", ao->userptr);
|
||||
|
||||
#ifndef DEBUG
|
||||
if(AOQUIET) snd_lib_error_set_handler(error_ignorer);
|
||||
#endif
|
||||
|
||||
pcm_name = ao->device ? ao->device : "default";
|
||||
if (snd_pcm_open(&pcm, pcm_name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
|
||||
if(!AOQUIET) error1("cannot open device %s", pcm_name);
|
||||
return -1;
|
||||
}
|
||||
ao->userptr = pcm;
|
||||
if (ao->format != -1) {
|
||||
/* we're going to play: initalize sample format */
|
||||
return initialize_device(ao);
|
||||
} else {
|
||||
/* query mode; sample format will be set for each query */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_alsa(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
snd_pcm_hw_params_t *hw;
|
||||
unsigned int rate;
|
||||
int supported_formats, i;
|
||||
|
||||
snd_pcm_hw_params_alloca(&hw);
|
||||
if (snd_pcm_hw_params_any(pcm, hw) < 0) {
|
||||
if(!AOQUIET) error("get_formats_alsa(): no configuration available");
|
||||
return -1;
|
||||
}
|
||||
if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
|
||||
return -1;
|
||||
if (snd_pcm_hw_params_set_channels(pcm, hw, ao->channels) < 0)
|
||||
return 0;
|
||||
rate = ao->rate;
|
||||
if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, NULL) < 0)
|
||||
return -1;
|
||||
if (!rates_match(ao->rate, rate))
|
||||
return 0;
|
||||
supported_formats = 0;
|
||||
for (i = 0; i < NUM_FORMATS; ++i) {
|
||||
if (snd_pcm_hw_params_test_format(pcm, hw, format_map[i].alsa) == 0)
|
||||
supported_formats |= format_map[i].mpg123;
|
||||
}
|
||||
return supported_formats;
|
||||
}
|
||||
|
||||
static int write_alsa(out123_handle *ao, unsigned char *buf, int bytes)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
snd_pcm_uframes_t frames;
|
||||
snd_pcm_sframes_t written;
|
||||
|
||||
frames = snd_pcm_bytes_to_frames(pcm, bytes);
|
||||
while
|
||||
( /* Try to write, recover if error, try again if recovery successful. */
|
||||
(written = snd_pcm_writei(pcm, buf, frames)) < 0
|
||||
&& snd_pcm_recover(pcm, (int)written, 0) == 0
|
||||
)
|
||||
{
|
||||
debug2("recovered from alsa issue %i while trying to write %lu frames", (int)written, (unsigned long)frames);
|
||||
}
|
||||
if(written < 0)
|
||||
{
|
||||
error1("Fatal problem with alsa output, error %i.", (int)written);
|
||||
return -1;
|
||||
}
|
||||
else return snd_pcm_frames_to_bytes(pcm, written);
|
||||
}
|
||||
|
||||
static void flush_alsa(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
|
||||
/* is this the optimal solution? - we should figure out what we really whant from this function */
|
||||
|
||||
debug("alsa drop");
|
||||
snd_pcm_drop(pcm);
|
||||
debug("alsa prepare");
|
||||
snd_pcm_prepare(pcm);
|
||||
debug("alsa flush done");
|
||||
}
|
||||
|
||||
static void drain_alsa(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
debug1("drain_alsa with %p", ao->userptr);
|
||||
snd_pcm_drain(pcm);
|
||||
}
|
||||
|
||||
static int close_alsa(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
debug1("close_alsa with %p", ao->userptr);
|
||||
if(pcm != NULL) /* be really generous for being called without any device opening */
|
||||
{
|
||||
ao->userptr = NULL; /* Should alsa do this or the module wrapper? */
|
||||
return snd_pcm_close(pcm);
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static int init_alsa(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_alsa;
|
||||
ao->flush = flush_alsa;
|
||||
ao->drain = drain_alsa;
|
||||
ao->write = write_alsa;
|
||||
ao->get_formats = get_formats_alsa;
|
||||
ao->close = close_alsa;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "alsa",
|
||||
/* description */ "Output audio using Advanced Linux Sound Architecture (ALSA).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_alsa,
|
||||
};
|
||||
|
||||
117
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/arts.c
vendored
Normal file
117
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/arts.c
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
arts: audio output via aRts Sound Daemon
|
||||
|
||||
copyright 2007-8 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 Stefan Lenselink (Stefan@lenselink.org)
|
||||
*/
|
||||
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <artsc.h>
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
arts_stream_t arse; /* That's short for ARts StrEam;-) */
|
||||
} mpg123_arts_t;
|
||||
|
||||
static int open_arts(out123_handle *ao)
|
||||
{
|
||||
short bits = 0;
|
||||
if(!ao) return -1;
|
||||
|
||||
if(ao->format < 0)
|
||||
{
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
}
|
||||
/* Trial and error revealed these two formats to work with aRts. */
|
||||
if(ao->format == MPG123_ENC_SIGNED_16) bits = 16;
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8) bits = 8;
|
||||
else return -1;
|
||||
|
||||
/* Initialize the aRts lib*/
|
||||
arts_init();
|
||||
/* Open a stream to the aRts server */
|
||||
((mpg123_arts_t*)ao->userptr)->arse = arts_play_stream( ao->rate, bits, ao->channels, "mpg123" );
|
||||
/* Yeah, black box and all... it's still a pointer that is NULL on error. */
|
||||
return (void*)((mpg123_arts_t*)ao->userptr)->arse == NULL ? -1 : 0;
|
||||
}
|
||||
|
||||
static int get_formats_arts(out123_handle *ao)
|
||||
{
|
||||
/* aRts runs not everything, but any rate. */
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_8;
|
||||
}
|
||||
|
||||
static int write_arts(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
/* PIPE the PCM forward to the aRts Sound Daemon */
|
||||
return arts_write( ((mpg123_arts_t*)ao->userptr)->arse , buf, len);
|
||||
}
|
||||
|
||||
static int close_arts(out123_handle *ao)
|
||||
{
|
||||
/* Close the connection! */
|
||||
arts_close_stream( ((mpg123_arts_t*)ao->userptr)->arse );
|
||||
/* Free the memory allocated*/
|
||||
arts_free();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_arts(out123_handle *ao)
|
||||
{
|
||||
/* aRts doesn't have a flush statement! */
|
||||
}
|
||||
|
||||
static int deinit_arts(out123_handle* ao)
|
||||
{
|
||||
if(ao->userptr)
|
||||
{
|
||||
free(ao->userptr);
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
arts_free();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_arts(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
ao->userptr = malloc(sizeof(mpg123_arts_t));
|
||||
if(ao->userptr == NULL)
|
||||
{
|
||||
error("Out of memory!");
|
||||
return -1;
|
||||
}
|
||||
/* clear it to have a consistent state */
|
||||
memset(ao->userptr, 0, sizeof(mpg123_arts_t));
|
||||
/* Set callbacks */
|
||||
ao->open = open_arts;
|
||||
ao->flush = flush_arts;
|
||||
ao->write = write_arts;
|
||||
ao->get_formats = get_formats_arts;
|
||||
ao->close = close_arts;
|
||||
ao->deinit = deinit_arts;
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "arts",
|
||||
/* description */ "Output audio using aRts Sound Daemon",
|
||||
/* revision */ "$Rev: $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_arts,
|
||||
};
|
||||
|
||||
|
||||
435
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/coreaudio.c
vendored
Normal file
435
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/coreaudio.c
vendored
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
coreaudio: audio output on MacOS X
|
||||
|
||||
copyright ?-2016 by the mpg123 project - free software under the terms of the GPL 2
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Guillaume Outters
|
||||
modified by Nicholas J Humfrey to use SFIFO code
|
||||
modified by Taihei Monma to use AudioUnit and AudioConverter APIs
|
||||
*/
|
||||
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
/* has been around since at least 10.4 */
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
/* Use AudioComponents API when compiling for >= 10.6, otherwise fall back to
|
||||
* Components Manager, which is deprecated since 10.8.
|
||||
* MAC_OS_X_VERSION_MIN_REQUIRED defaults to the host system version and can be
|
||||
* governed by MACOSX_DEPLOYMENT_TARGET environment variable and
|
||||
* -mmacosx-version-min= when running the compiler. */
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 20000
|
||||
#define HAVE_AUDIOCOMPONENTS 1
|
||||
#endif
|
||||
|
||||
#if HAVE_AUDIOCOMPONENTS
|
||||
#define MPG123_AUDIOCOMPONENTDESCRIPTION AudioComponentDescription
|
||||
#define MPG123_AUDIOCOMPONENT AudioComponent
|
||||
#define MPG123_AUDIOCOMPONENTFINDNEXT AudioComponentFindNext
|
||||
/* Funky API twist: AudioUnit is actually typedef'd AudioComponentInstance */
|
||||
#define MPG123_AUDIOCOMPONENTINSTANCENEW AudioComponentInstanceNew
|
||||
#define MPG123_AUDIOCOMPONENTINSTANCEDISPOSE AudioComponentInstanceDispose
|
||||
#else
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#define MPG123_AUDIOCOMPONENTDESCRIPTION ComponentDescription
|
||||
#define MPG123_AUDIOCOMPONENT Component
|
||||
#define MPG123_AUDIOCOMPONENTFINDNEXT FindNextComponent
|
||||
#define MPG123_AUDIOCOMPONENTINSTANCENEW OpenAComponent
|
||||
#define MPG123_AUDIOCOMPONENTINSTANCEDISPOSE CloseComponent
|
||||
#endif
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Including the sfifo code locally, to avoid module linkage issues. */
|
||||
#define SFIFO_STATIC
|
||||
#include "sfifo.c"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* Duration of the ring buffer in seconds.
|
||||
Is that all that there is to tunable latency?
|
||||
Size of 200 ms should be enough for a default value, rare is the
|
||||
hardware that actually allows such large buffers. */
|
||||
#define FIFO_DURATION (ao->device_buffer > 0. ? ao->device_buffer : 0.2)
|
||||
|
||||
|
||||
typedef struct mpg123_coreaudio
|
||||
{
|
||||
AudioConverterRef converter;
|
||||
AudioUnit outputUnit;
|
||||
int open;
|
||||
char play;
|
||||
int channels;
|
||||
int bps;
|
||||
int play_done;
|
||||
int decode_done;
|
||||
|
||||
/* Convertion buffer */
|
||||
unsigned char * buffer;
|
||||
size_t buffer_size;
|
||||
|
||||
/* Ring buffer */
|
||||
sfifo_t fifo;
|
||||
|
||||
} mpg123_coreaudio_t;
|
||||
|
||||
|
||||
|
||||
static OSStatus playProc(AudioConverterRef inAudioConverter,
|
||||
UInt32 *ioNumberDataPackets,
|
||||
AudioBufferList *outOutputData,
|
||||
AudioStreamPacketDescription **outDataPacketDescription,
|
||||
void* inClientData)
|
||||
{
|
||||
out123_handle *ao = (out123_handle*)inClientData;
|
||||
mpg123_coreaudio_t *ca = (mpg123_coreaudio_t *)ao->userptr;
|
||||
long n;
|
||||
|
||||
/* This is not actually a loop. See the early break. */
|
||||
for(n = 0; n < outOutputData->mNumberBuffers; n++)
|
||||
{
|
||||
unsigned int wanted = *ioNumberDataPackets * ca->channels * ca->bps;
|
||||
unsigned char *dest;
|
||||
unsigned int read;
|
||||
int avail;
|
||||
|
||||
/* Any buffer count > 1 would wreck havoc with this code. */
|
||||
if(n > 0)
|
||||
break;
|
||||
|
||||
if(ca->buffer_size < wanted) {
|
||||
debug1("Allocating %d byte sample conversion buffer", wanted);
|
||||
ca->buffer = realloc( ca->buffer, wanted);
|
||||
ca->buffer_size = wanted;
|
||||
}
|
||||
dest = ca->buffer;
|
||||
if(!dest)
|
||||
return -1;
|
||||
|
||||
/* Only play if we have data left */
|
||||
while((avail=sfifo_used( &ca->fifo )) < wanted && !ca->decode_done)
|
||||
{
|
||||
int ms = (wanted-avail)/ao->framesize*1000/ao->rate;
|
||||
debug3("waiting for more input, %d ms missing (%i < %u)"
|
||||
, ms, avail, wanted);
|
||||
usleep(ms*100); /* Wait for 1/10th of the missing duration. Might want to adjust. */
|
||||
}
|
||||
if(avail > wanted)
|
||||
avail = wanted;
|
||||
else if(ca->decode_done)
|
||||
ca->play_done = 1;
|
||||
|
||||
/* Read audio from FIFO to CoreAudio's buffer */
|
||||
read = sfifo_read(&ca->fifo, dest, avail);
|
||||
|
||||
if(read!=avail)
|
||||
warning2("Error reading from the ring buffer (avail=%u, read=%u).\n", avail, read);
|
||||
|
||||
outOutputData->mBuffers[n].mDataByteSize = read;
|
||||
outOutputData->mBuffers[n].mData = dest;
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static OSStatus convertProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
|
||||
UInt32 inNumFrames, AudioBufferList *ioData)
|
||||
{
|
||||
AudioStreamPacketDescription* outPacketDescription = NULL;
|
||||
out123_handle *ao = (out123_handle*)inRefCon;
|
||||
mpg123_coreaudio_t *ca = (mpg123_coreaudio_t *)ao->userptr;
|
||||
OSStatus err= noErr;
|
||||
|
||||
err = AudioConverterFillComplexBuffer(ca->converter, playProc, inRefCon, &inNumFrames, ioData, outPacketDescription);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int open_coreaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_coreaudio_t* ca = (mpg123_coreaudio_t*)ao->userptr;
|
||||
UInt32 size;
|
||||
MPG123_AUDIOCOMPONENTDESCRIPTION desc;
|
||||
MPG123_AUDIOCOMPONENT comp;
|
||||
AudioStreamBasicDescription inFormat;
|
||||
AudioStreamBasicDescription outFormat;
|
||||
AURenderCallbackStruct renderCallback;
|
||||
Boolean outWritable;
|
||||
|
||||
/* Initialize our environment */
|
||||
ca->play = 0;
|
||||
ca->buffer = NULL;
|
||||
ca->buffer_size = 0;
|
||||
ca->play_done = 0;
|
||||
ca->decode_done = 0;
|
||||
|
||||
/* Get the default audio output unit */
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
#if TARGET_OS_IPHONE
|
||||
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
#else
|
||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
#endif
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
comp = MPG123_AUDIOCOMPONENTFINDNEXT(NULL, &desc);
|
||||
if(comp == NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioComponentFindNext failed");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(MPG123_AUDIOCOMPONENTINSTANCENEW(comp, &(ca->outputUnit)))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioComponentInstanceNew failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if(AudioUnitInitialize(ca->outputUnit))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioUnitInitialize failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Specify the output PCM format */
|
||||
AudioUnitGetPropertyInfo(ca->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &size, &outWritable);
|
||||
if(AudioUnitGetProperty(ca->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outFormat, &size))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioUnitGetProperty(kAudioUnitProperty_StreamFormat) failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if(AudioUnitSetProperty(ca->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outFormat, size))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Specify the input PCM format */
|
||||
ca->channels = ao->channels;
|
||||
inFormat.mSampleRate = ao->rate;
|
||||
inFormat.mChannelsPerFrame = ao->channels;
|
||||
inFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
#ifdef _BIG_ENDIAN
|
||||
inFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
|
||||
#else
|
||||
inFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
||||
#endif
|
||||
|
||||
switch(ao->format)
|
||||
{
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
inFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
ca->bps = 2;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
inFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
ca->bps = 1;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
ca->bps = 1;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_32:
|
||||
inFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
ca->bps = 4;
|
||||
break;
|
||||
case MPG123_ENC_FLOAT_32:
|
||||
inFormat.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
|
||||
ca->bps = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
inFormat.mBitsPerChannel = ca->bps << 3;
|
||||
inFormat.mBytesPerPacket = ca->bps*inFormat.mChannelsPerFrame;
|
||||
inFormat.mFramesPerPacket = 1;
|
||||
inFormat.mBytesPerFrame = ca->bps*inFormat.mChannelsPerFrame;
|
||||
|
||||
/* Add our callback - but don't start it yet */
|
||||
memset(&renderCallback, 0, sizeof(AURenderCallbackStruct));
|
||||
renderCallback.inputProc = convertProc;
|
||||
renderCallback.inputProcRefCon = ao;
|
||||
if(AudioUnitSetProperty(ca->outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(AURenderCallbackStruct)))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioUnitSetProperty(kAudioUnitProperty_SetRenderCallback) failed");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
/* Open an audio I/O stream and create converter */
|
||||
if (ao->rate > 0 && ao->channels >0 ) {
|
||||
int ringbuffer_len;
|
||||
|
||||
if(AudioConverterNew(&inFormat, &outFormat, &(ca->converter)))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioConverterNew failed");
|
||||
return(-1);
|
||||
}
|
||||
if(ao->channels == 1) {
|
||||
SInt32 channelMap[2] = { 0, 0 };
|
||||
if(AudioConverterSetProperty(ca->converter, kAudioConverterChannelMap, sizeof(channelMap), channelMap))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioConverterSetProperty(kAudioConverterChannelMap) failed");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise FIFO */
|
||||
ringbuffer_len = ao->rate * FIFO_DURATION * ca->bps * ao->channels;
|
||||
debug2( "Allocating %d byte ring-buffer (%f seconds)", ringbuffer_len, (float)FIFO_DURATION);
|
||||
sfifo_init( &ca->fifo, ringbuffer_len );
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int get_formats_coreaudio(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_SIGNED_8|MPG123_ENC_UNSIGNED_8|MPG123_ENC_SIGNED_32|MPG123_ENC_FLOAT_32;
|
||||
}
|
||||
|
||||
static int write_coreaudio(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
mpg123_coreaudio_t* ca = (mpg123_coreaudio_t*)ao->userptr;
|
||||
int len_remain = len;
|
||||
|
||||
/* Some busy waiting, but feed what is possible. */
|
||||
while(len_remain) /* Note: input len is multiple of framesize! */
|
||||
{
|
||||
int block = sfifo_space(&ca->fifo);
|
||||
block -= block % ao->framesize;
|
||||
if(block > len_remain)
|
||||
block = len_remain;
|
||||
if(block)
|
||||
{
|
||||
sfifo_write(&ca->fifo, buf, block);
|
||||
len_remain -= block;
|
||||
buf += block;
|
||||
/* Start playback now that we have something to play */
|
||||
if(!ca->play && (sfifo_used(&ca->fifo) > (sfifo_size(&ca->fifo)/2)))
|
||||
{
|
||||
if(AudioOutputUnitStart(ca->outputUnit))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioOutputUnitStart failed");
|
||||
return(-1);
|
||||
}
|
||||
ca->play = 1;
|
||||
}
|
||||
}
|
||||
/* If there is no room, then sleep for a bit, but not too long. */
|
||||
if(len_remain)
|
||||
usleep( (0.1*FIFO_DURATION) * 1000000 );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_coreaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_coreaudio_t* ca = (mpg123_coreaudio_t*)ao->userptr;
|
||||
|
||||
if (ca) {
|
||||
ca->decode_done = 1;
|
||||
while(!ca->play_done && ca->play)
|
||||
usleep((0.1*FIFO_DURATION)*1000000);
|
||||
/* No matter the error code, we want to close it (by brute force if necessary) */
|
||||
AudioOutputUnitStop(ca->outputUnit);
|
||||
AudioUnitUninitialize(ca->outputUnit);
|
||||
MPG123_AUDIOCOMPONENTINSTANCEDISPOSE(ca->outputUnit);
|
||||
AudioConverterDispose(ca->converter);
|
||||
|
||||
/* Free the ring buffer */
|
||||
sfifo_close( &ca->fifo );
|
||||
|
||||
/* Free the conversion buffer */
|
||||
if (ca->buffer) {
|
||||
free( ca->buffer );
|
||||
ca->buffer = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_coreaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_coreaudio_t* ca = (mpg123_coreaudio_t*)ao->userptr;
|
||||
|
||||
/* Flush AudioConverter's buffer */
|
||||
if(AudioConverterReset(ca->converter))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioConverterReset failed");
|
||||
}
|
||||
|
||||
/* Empty out the ring buffer */
|
||||
sfifo_flush( &ca->fifo );
|
||||
}
|
||||
|
||||
static int deinit_coreaudio(out123_handle* ao)
|
||||
{
|
||||
/* Free up memory */
|
||||
if (ao->userptr) {
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_coreaudio(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_coreaudio;
|
||||
ao->flush = flush_coreaudio;
|
||||
ao->write = write_coreaudio;
|
||||
ao->get_formats = get_formats_coreaudio;
|
||||
ao->close = close_coreaudio;
|
||||
ao->deinit = deinit_coreaudio;
|
||||
|
||||
/* Allocate memory for data structure */
|
||||
ao->userptr = malloc( sizeof( mpg123_coreaudio_t ) );
|
||||
if (ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("failed to malloc memory for 'mpg123_coreaudio_t'");
|
||||
return -1;
|
||||
}
|
||||
memset( ao->userptr, 0, sizeof(mpg123_coreaudio_t) );
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "coreaudio",
|
||||
/* description */ "Output audio using Mac OS X's CoreAudio.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_coreaudio,
|
||||
};
|
||||
|
||||
|
||||
84
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/dummy.c
vendored
Normal file
84
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/dummy.c
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
dummy: dummy audio output
|
||||
|
||||
copyright ?-2006 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
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int open_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("open_dummy()");
|
||||
if(ao->format < 0)
|
||||
{
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_formats_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("get_formats_dummy()");
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
static int write_dummy(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
debug("write_dummy()");
|
||||
return len;
|
||||
}
|
||||
|
||||
static void flush_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("flush_dummy()");
|
||||
}
|
||||
|
||||
static int close_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("close_dummy()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deinit_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("deinit_dummy()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_dummy(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
debug("init_dummy()");
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_dummy;
|
||||
ao->flush = flush_dummy;
|
||||
ao->write = write_dummy;
|
||||
ao->get_formats = get_formats_dummy;
|
||||
ao->close = close_dummy;
|
||||
ao->deinit = deinit_dummy;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "dummy",
|
||||
/* description */ "Dummy audio output - does not output audio.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_dummy,
|
||||
};
|
||||
|
||||
169
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/esd.c
vendored
Normal file
169
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/esd.c
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
esd: audio output for ESounD (highly untested nowadays (?))
|
||||
|
||||
copyright ?-2006 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 Eric B. Mitchell ("esd port" should be this file...)
|
||||
*/
|
||||
|
||||
/* First the common header, including config.h
|
||||
...this is important for stuff like _FILE_OFFSET_BITS */
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <esd.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef SOLARIS
|
||||
#include <stropts.h>
|
||||
#include <sys/conf.h>
|
||||
#endif
|
||||
#ifdef NETBSD
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/audioio.h>
|
||||
#endif
|
||||
#include "debug.h"
|
||||
|
||||
static unsigned esd_rate = 0, esd_format = 0, esd_channels = 0;
|
||||
|
||||
|
||||
static int open_esound(out123_handle *ao)
|
||||
{
|
||||
esd_format_t format = ESD_STREAM | ESD_PLAY;
|
||||
|
||||
if (!esd_rate)
|
||||
{
|
||||
int esd;
|
||||
esd_server_info_t *info;
|
||||
esd_format_t fmt;
|
||||
|
||||
if ((esd = esd_open_sound(NULL)) >= 0)
|
||||
{
|
||||
info = esd_get_server_info(esd);
|
||||
esd_rate = info->rate;
|
||||
fmt = info->format;
|
||||
esd_free_server_info(info);
|
||||
esd_close(esd);
|
||||
}
|
||||
else
|
||||
{
|
||||
esd_rate = esd_audio_rate;
|
||||
fmt = esd_audio_format;
|
||||
}
|
||||
esd_format = MPG123_ENC_UNSIGNED_8;
|
||||
|
||||
if ((fmt & ESD_MASK_BITS) == ESD_BITS16)
|
||||
esd_format |= MPG123_ENC_SIGNED_16;
|
||||
esd_channels = fmt & ESD_MASK_CHAN;
|
||||
}
|
||||
|
||||
if (ao->format == -1)
|
||||
ao->format = esd_format;
|
||||
else if (!(ao->format & esd_format))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Unsupported audio format: %d\n", ao->format);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (ao->format & MPG123_ENC_SIGNED_16)
|
||||
format |= ESD_BITS16;
|
||||
else if (ao->format & MPG123_ENC_UNSIGNED_8)
|
||||
format |= ESD_BITS8;
|
||||
else assert(0);
|
||||
|
||||
if (ao->channels == -1) ao->channels = 2;
|
||||
else if (ao->channels <= 0 || ao->channels > esd_channels)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Unsupported no of channels: %d\n", ao->channels);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (ao->channels == 1)
|
||||
format |= ESD_MONO;
|
||||
else if (ao->channels == 2)
|
||||
format |= ESD_STEREO;
|
||||
else assert(0);
|
||||
|
||||
if (ao->rate == -1) ao->rate = esd_rate;
|
||||
else if (ao->rate > esd_rate)
|
||||
return -1;
|
||||
|
||||
ao->fn = esd_play_stream_fallback(format, ao->rate, ao->device, "mpg123");
|
||||
return (ao->fn);
|
||||
}
|
||||
|
||||
static int get_formats_esound (out123_handle *ao)
|
||||
{
|
||||
if (0 < ao->channels && ao->channels <= esd_channels
|
||||
&& 0 < ao->rate && ao->rate <= esd_rate)
|
||||
{
|
||||
return esd_format;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int write_esound(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_esound(out123_handle *ao)
|
||||
{
|
||||
close (ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SOLARIS
|
||||
static void flush_esound (out123_handle *ao)
|
||||
{
|
||||
ioctl (ao->fn, I_FLUSH, FLUSHRW);
|
||||
}
|
||||
#else
|
||||
#ifdef NETBSD
|
||||
static void flush_esound (out123_handle *ao)
|
||||
{
|
||||
ioctl (ao->fn, AUDIO_FLUSH, 0);
|
||||
}
|
||||
#else
|
||||
/* Dunno what to do on Linux and Cygwin, but the func must be at least defined! */
|
||||
static void flush_esound (out123_handle *ao)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
static int init_esound(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_esound;
|
||||
ao->flush = flush_esound;
|
||||
ao->write = write_esound;
|
||||
ao->get_formats = get_formats_esound;
|
||||
ao->close = close_esound;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "esd",
|
||||
/* description */ "Output audio using ESounD (The Enlightened Sound Daemon).",
|
||||
/* revision */ "$Rev: 3915 $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_esound,
|
||||
};
|
||||
184
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/hp.c
vendored
Normal file
184
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/hp.c
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
hp: audio output for HP-UX
|
||||
|
||||
copyright ?-2006 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
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/audio.h>
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
static int set_rate(out123_handle *ao)
|
||||
{
|
||||
if(ao->rate >= 0) {
|
||||
return ioctl(ao->fn,AUDIO_SET_SAMPLE_RATE,ao->rate);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int set_channels(out123_handle *ao)
|
||||
{
|
||||
if(ao->channels<0) return 0;
|
||||
return ioctl(ao->fn,AUDIO_SET_CHANNELS,ao->channels);
|
||||
}
|
||||
|
||||
static int set_format(out123_handle *ao)
|
||||
{
|
||||
int fmt;
|
||||
|
||||
switch(ao->format) {
|
||||
case -1:
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
fmt = MPG123_ENC_LINEAR16BIT;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
error("unsigned 8 bit linear not supported");
|
||||
return -1;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
error("signed 8 bit linear not supported");
|
||||
return -1;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
fmt = MPG123_ENC_ALAW;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
fmt = MPG123_ENC_ULAW;
|
||||
break;
|
||||
}
|
||||
return ioctl(ao->fn,AUDIO_SET_DATA_FORMAT,fmt);
|
||||
}
|
||||
|
||||
static int get_formats(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
static int reset_parameters(out123_handle *ao)
|
||||
{
|
||||
int ret;
|
||||
ret = set_format(ai);
|
||||
if(ret >= 0)
|
||||
ret = set_channels_hp(ai);
|
||||
if(ret >= 0)
|
||||
ret = set_rate_hp(ai);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int open_hp(out123_handle *ao)
|
||||
{
|
||||
struct audio_describe ades;
|
||||
struct audio_gain again;
|
||||
int i,audio;
|
||||
|
||||
ao->fn = open("/dev/audio",O_RDWR);
|
||||
|
||||
if(ao->fn < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
ioctl(ao->fn,AUDIO_DESCRIBE,&ades);
|
||||
|
||||
if(ao->gain != -1)
|
||||
{
|
||||
if(ao->gain > ades.max_transmit_gain)
|
||||
{
|
||||
error("your gainvalue was to high -> set to maximum.");
|
||||
ao->gain = ades.max_transmit_gain;
|
||||
}
|
||||
if(ao->gain < ades.min_transmit_gain)
|
||||
{
|
||||
error("your gainvalue was to low -> set to minimum.");
|
||||
ao->gain = ades.min_transmit_gain;
|
||||
}
|
||||
again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1;
|
||||
ioctl(ao->fn,AUDIO_GET_GAINS,&again);
|
||||
again.cgain[0].transmit_gain = ao->gain;
|
||||
again.cgain[1].transmit_gain = ao->gain;
|
||||
again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1;
|
||||
ioctl(ao->fn,AUDIO_SET_GAINS,&again);
|
||||
}
|
||||
|
||||
if(ao->flags != -1)
|
||||
{
|
||||
if(ao->flags & OUT123_INTERNAL_SPEAKER)
|
||||
ioctl(ao->fn,AUDIO_SET_OUTPUT,OUT123_SPEAKER);
|
||||
else if(ao->flags & OUT123_HEADPHONES)
|
||||
ioctl(ao->fn,AUDIO_SET_OUTPUT,OUT123_HEADPHONE);
|
||||
else if(ao->flags & OUT123_LINE_OUT)
|
||||
ioctl(ao->fn,AUDIO_SET_OUTPUT,OUT123_LINE);
|
||||
}
|
||||
|
||||
if(ao->rate == -1)
|
||||
ao->rate = 44100;
|
||||
|
||||
for(i=0;i<ades.nrates;i++)
|
||||
{
|
||||
if(ao->rate == ades.sample_rate[i])
|
||||
break;
|
||||
}
|
||||
if(i == ades.nrates)
|
||||
{
|
||||
error1("Can't set sample-rate to %ld.\n",ao->rate);
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if(reset_parameters(ai) < 0)
|
||||
return -1;
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int write_hp(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_hp(out123_handle *ao)
|
||||
{
|
||||
close (ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_hp(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int init_hp(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_hp;
|
||||
ao->flush = flush_hp;
|
||||
ao->write = write_hp;
|
||||
ao->get_formats = get_formats_hp;
|
||||
ao->close = close_hp;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "hp",
|
||||
/* description */ "Output audio HP-UX",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_hp,
|
||||
};
|
||||
618
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/jack.c
vendored
Normal file
618
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/jack.c
vendored
Normal file
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
jack: audio output via JACK Audio Connection Kit
|
||||
|
||||
copyright 2006-2016 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 Nicholas J. Humfrey
|
||||
|
||||
I reworked the processing logic. Only one ringbuffer, deinterleaving in the
|
||||
processing callback. A semaphore to avoid using usleep() for waiting. Up
|
||||
to 99 channels. Only float input (ensures that libmpg123 selects f32
|
||||
encoding). This is still a hack to shoehorn the JACK API into our model.
|
||||
|
||||
Damn. I'm wary of he semaphore. I'm sure I constructed a deadlock there.
|
||||
There's always a deadlock. --ThOr
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <jack/jack.h>
|
||||
#include <jack/ringbuffer.h>
|
||||
/* Using some pthread to provide synchronization between process callback
|
||||
and writer part. The JACK API is not meant for this. Libpthread is
|
||||
pulled in as libjack dependency anyway. */
|
||||
#include <semaphore.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct {
|
||||
int alive;
|
||||
sem_t sem; /* semaphore to avoid busy waiting */
|
||||
int channels;
|
||||
int encoding;
|
||||
int framesize;
|
||||
jack_default_audio_sample_t **ports_buf;
|
||||
jack_port_t **ports;
|
||||
jack_ringbuffer_t *rb;
|
||||
size_t rb_size; /* in bytes */
|
||||
jack_client_t *client;
|
||||
char *procbuf;
|
||||
size_t procbuf_frames; /* in PCM frames */
|
||||
} jack_handle_t, *jack_handle_ptr;
|
||||
|
||||
static jack_handle_t* alloc_jack_handle(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle=NULL;
|
||||
int i;
|
||||
|
||||
handle = malloc(sizeof(jack_handle_t));
|
||||
if (!handle)
|
||||
return NULL;
|
||||
handle->channels = ao->channels;
|
||||
handle->encoding = ao->format;
|
||||
handle->framesize = ao->framesize;
|
||||
handle->rb = NULL;
|
||||
handle->ports_buf = malloc( sizeof(jack_default_audio_sample_t*)
|
||||
* ao->channels );
|
||||
handle->ports = malloc(sizeof(jack_port_t*)*ao->channels);
|
||||
if(!handle->ports_buf || !handle->ports)
|
||||
{
|
||||
if(handle->ports_buf)
|
||||
free(handle->ports_buf);
|
||||
if(handle->ports)
|
||||
free(handle->ports);
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
for(i=0; i<ao->channels; ++i)
|
||||
{
|
||||
handle->ports_buf[i] = NULL;
|
||||
handle->ports[i] = NULL;
|
||||
}
|
||||
if(sem_init(&handle->sem, 0, 0))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Semaphore init failed.");
|
||||
free(handle->ports_buf);
|
||||
free(handle->ports);
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
handle->alive = 0;
|
||||
handle->client = NULL;
|
||||
handle->procbuf = NULL;
|
||||
handle->rb_size = 0;
|
||||
handle->procbuf_frames = 0;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
static void free_jack_handle( jack_handle_t* handle )
|
||||
{
|
||||
int i;
|
||||
|
||||
if(handle->ports)
|
||||
{
|
||||
if(handle->client)
|
||||
for(i=0; i<handle->channels; i++)
|
||||
{
|
||||
/* Close the port for channel*/
|
||||
if(handle->ports[i])
|
||||
jack_port_unregister(handle->client, handle->ports[i]);
|
||||
}
|
||||
free(handle->ports);
|
||||
}
|
||||
if(handle->ports_buf)
|
||||
free(handle->ports_buf);
|
||||
/* Free up the ring buffer for channel*/
|
||||
if(handle->rb)
|
||||
jack_ringbuffer_free(handle->rb);
|
||||
if (handle->client)
|
||||
jack_client_close(handle->client);
|
||||
if (handle->procbuf)
|
||||
free(handle->procbuf);
|
||||
sem_destroy(&handle->sem);
|
||||
free(handle);
|
||||
}
|
||||
|
||||
|
||||
static int process_callback( jack_nframes_t nframes, void *arg )
|
||||
{
|
||||
int c;
|
||||
jack_handle_t* handle = (jack_handle_t*)arg;
|
||||
size_t to_read = nframes;
|
||||
|
||||
for(c=0; c<handle->channels; ++c)
|
||||
handle->ports_buf[c] =
|
||||
jack_port_get_buffer(handle->ports[c], nframes);
|
||||
|
||||
/* One ringbuffer to rule them all, getting interleaved data piecewise
|
||||
and appending to non-interleaved buffers. */
|
||||
while(to_read)
|
||||
{
|
||||
/* Need to read into temporary storage, then deinterleave to JACK
|
||||
buffers. */
|
||||
size_t got_piece;
|
||||
size_t avail_piece;
|
||||
size_t piece = to_read > handle->procbuf_frames
|
||||
? handle->procbuf_frames
|
||||
: to_read;
|
||||
/* Ensure we get only full PCM frames by checking available byte count
|
||||
and reducing expectation. */
|
||||
avail_piece = jack_ringbuffer_read_space(handle->rb)/handle->framesize;
|
||||
got_piece = jack_ringbuffer_read( handle->rb
|
||||
, handle->procbuf, (avail_piece > piece ? piece : avail_piece)
|
||||
* handle->framesize ) / handle->framesize;
|
||||
debug2( "fetched %"SIZE_P" frames from ringbuffer (wanted %"SIZE_P")"
|
||||
, (size_p)got_piece, (size_p)piece );
|
||||
/* If this is the last piece, fill up, not time to wait. */
|
||||
if(to_read > piece)
|
||||
piece = got_piece; /* We got further loop cycle(s) to get the rest. */
|
||||
else
|
||||
{
|
||||
if(piece > got_piece)
|
||||
{
|
||||
debug("filling up with zeros");
|
||||
bzero( handle->procbuf+got_piece*handle->framesize
|
||||
, (piece-got_piece)*handle->framesize );
|
||||
}
|
||||
}
|
||||
/* Now extract the pieces for the channels. */
|
||||
for (c=0; c < handle->channels; ++c)
|
||||
{
|
||||
size_t n;
|
||||
jack_default_audio_sample_t *dst = handle->ports_buf[c];
|
||||
if(handle->encoding == MPG123_ENC_FLOAT_32)
|
||||
{
|
||||
float* src = (float*)handle->procbuf;
|
||||
for(n=0; n<piece; ++n)
|
||||
*(dst++) = src[(n*handle->channels)+c];
|
||||
}
|
||||
else /* MPG123_ENC_FLOAT_64 */
|
||||
{
|
||||
double* src = (double*)handle->procbuf;
|
||||
for(n=0; n<piece; ++n)
|
||||
*(dst++) = src[(n*handle->channels)+c];
|
||||
}
|
||||
/* Store output buffer offset. */
|
||||
handle->ports_buf[c] = dst;
|
||||
}
|
||||
/* Give the writer a hint about the time passed. */
|
||||
sem_post(&handle->sem);
|
||||
to_read -= piece;
|
||||
}
|
||||
/* Success*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is triggered on server shutdown and very much necessary to avoid
|
||||
out123 hanging on the processor semaphore. */
|
||||
static void shutdown_callback(void *arg)
|
||||
{
|
||||
jack_handle_t* handle = (jack_handle_t*)arg;
|
||||
handle->alive = 0;
|
||||
sem_post(&handle->sem);
|
||||
debug("shutdown_callback()");
|
||||
}
|
||||
|
||||
/* connect to jack ports named in the NULL-terminated wishlist */
|
||||
static int real_connect_jack_ports(out123_handle *ao
|
||||
, jack_handle_t* handle, const char** wishlist)
|
||||
{
|
||||
const char **wish = wishlist;
|
||||
int ch, err;
|
||||
int ch_wrap = 0, wish_wrap = 0;
|
||||
|
||||
if(!wish)
|
||||
return 0;
|
||||
if(wish != NULL && *wish == NULL)
|
||||
return 1; /* success, nothing connected as wanted */
|
||||
ch=0;
|
||||
/* Connect things as long as there are sources or sinks left. */
|
||||
while(!wish_wrap || !ch_wrap)
|
||||
{
|
||||
const char* in = jack_port_name(handle->ports[ch]);
|
||||
|
||||
if((err = jack_connect(handle->client, in, *wish)) != 0 && err != EEXIST)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error4( "connect_jack_ports(): failed to jack_connect() ch%i (%s) to %s: %d"
|
||||
, ch, in ? in : "<nil>", *wish, err );
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
Increment channel and wishlist, both possibly wrapping around, to
|
||||
ensure we connected all channels to some output port and provided
|
||||
some input to all ports in the wishlist. Both cases of less channels
|
||||
than output ports (splitting) and more channels than output ports
|
||||
(downmix) are sensible.
|
||||
*/
|
||||
if(++ch == handle->channels)
|
||||
{
|
||||
ch = 0;
|
||||
++ch_wrap;
|
||||
}
|
||||
if(!*(++wish))
|
||||
{
|
||||
wish = wishlist;
|
||||
++wish_wrap;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* crude way of automatically connecting up jack ports */
|
||||
/* 0 on error */
|
||||
static int autoconnect_jack_ports(out123_handle *ao, jack_handle_t* handle)
|
||||
{
|
||||
const char **all_ports;
|
||||
unsigned int ch=0;
|
||||
int err,i;
|
||||
|
||||
/* Get a list of all the jack ports*/
|
||||
all_ports = jack_get_ports (handle->client, NULL, NULL, JackPortIsInput);
|
||||
if(!all_ports)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("connect_jack_ports(): jack_get_ports() returned NULL.");
|
||||
return 0;
|
||||
}
|
||||
/* Step through each port name*/
|
||||
for (i = 0; all_ports[i]; ++i)
|
||||
{
|
||||
const char* in = jack_port_name( handle->ports[ch] );
|
||||
const char* out = all_ports[i];
|
||||
|
||||
if ((err = jack_connect(handle->client, in, out)) != 0 && err != EEXIST)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("connect_jack_ports(): failed to jack_connect() ports: %d",err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Found enough ports ?*/
|
||||
if (++ch >= handle->channels) break;
|
||||
}
|
||||
jack_free(all_ports);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int connect_jack_ports(out123_handle *ao
|
||||
, jack_handle_t* handle)
|
||||
{
|
||||
debug1("connect_jack_ports with dev=%s", ao->device ? ao->device : "<nil>");
|
||||
if(ao->device==NULL || strcmp(ao->device, "auto")==0)
|
||||
return autoconnect_jack_ports(ao, handle);
|
||||
else
|
||||
{
|
||||
/* Parse device for a set of ports, comma separated. */
|
||||
const char** wishlist; /* Channels and end marker. */
|
||||
int wish_channels = 1; /* Numper of entries in wishlist. */
|
||||
char *devcopy, *chr;
|
||||
int ret;
|
||||
int c;
|
||||
size_t len;
|
||||
len = strlen(ao->device);
|
||||
/* We connect as many JACK ports as desired, possibly duplicating. */
|
||||
for(chr=ao->device; *chr; ++chr)
|
||||
if(*chr == ',')
|
||||
++wish_channels;
|
||||
debug1("wish_channels: %i", wish_channels);
|
||||
wishlist = malloc(sizeof(char*)*(wish_channels+1));
|
||||
devcopy = compat_strdup(ao->device);
|
||||
if(devcopy == NULL || wishlist == NULL)
|
||||
{
|
||||
if(devcopy)
|
||||
free(devcopy);
|
||||
if(wishlist)
|
||||
free(wishlist);
|
||||
if(!AOQUIET)
|
||||
error("OOM");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(c=0;c<=wish_channels;++c)
|
||||
wishlist[c] = NULL;
|
||||
if(len && strcmp(devcopy, "none"))
|
||||
{
|
||||
size_t i=0;
|
||||
wishlist[0] = devcopy;
|
||||
for(c=0;c<wish_channels;++c)
|
||||
{
|
||||
while(devcopy[i] != 0 && devcopy[i] != ',') ++i;
|
||||
debug2("devcopy[%"SIZE_P"]=%i", i, devcopy[i]);
|
||||
if(devcopy[i] == ',')
|
||||
{
|
||||
/* Terminate previous port name, assign next one. */
|
||||
devcopy[i++] = 0;
|
||||
debug2("terminaled wish %i: %s", c, wishlist[c]);
|
||||
if(c+1 < wish_channels)
|
||||
wishlist[c+1] = devcopy+i;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(wishlist[0] == NULL && !AOQUIET)
|
||||
warning("Not connecting up jack ports as requested.");
|
||||
|
||||
ret = real_connect_jack_ports(ao, handle, wishlist);
|
||||
free(devcopy);
|
||||
free(wishlist);
|
||||
return ret;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void drain_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
|
||||
debug("drain_jack().");
|
||||
|
||||
do errno = 0;
|
||||
while(sem_trywait(&handle->sem) == 0 || errno == EINTR);
|
||||
/* For some reason, a single byte is reserved by JACK?! */
|
||||
while( handle && handle->alive && handle->rb
|
||||
&& jack_ringbuffer_write_space(handle->rb)+1 < handle->rb_size )
|
||||
{
|
||||
debug2( "JACK close wait %"SIZE_P" < %"SIZE_P"\n"
|
||||
, (size_p)jack_ringbuffer_write_space(handle->rb)
|
||||
, (size_p)handle->rb_size );
|
||||
sem_wait(&handle->sem);
|
||||
}
|
||||
}
|
||||
|
||||
static int close_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
|
||||
debug("close_jack().");
|
||||
/* Close and shutdown*/
|
||||
if(handle)
|
||||
{
|
||||
free_jack_handle(handle);
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int open_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle=NULL;
|
||||
jack_options_t jopt = JackNullOption|JackNoStartServer;
|
||||
jack_status_t jstat = 0;
|
||||
unsigned int i;
|
||||
char *realname;
|
||||
|
||||
debug("jack open");
|
||||
if(!ao)
|
||||
return -1;
|
||||
|
||||
/* Return if already open*/
|
||||
if(ao->userptr)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("audio device is already open.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The initial open lets me choose the settings. */
|
||||
if (ao->format==-1)
|
||||
{
|
||||
ao->format = MPG123_ENC_FLOAT_32;
|
||||
ao->channels = 2;
|
||||
/* Really need a framesize defined for callback. */
|
||||
ao->framesize = 2*4;
|
||||
}
|
||||
else if(!(ao->format & MPG123_ENC_FLOAT))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("JACK only wants float!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create some storage for ourselves*/
|
||||
if((handle = alloc_jack_handle(ao)) == NULL)
|
||||
return -1;
|
||||
ao->userptr = (void*)handle;
|
||||
|
||||
/* Register with Jack*/
|
||||
if((handle->client = jack_client_open(ao->name, jopt, &jstat)) == 0)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Failed to open jack client: 0x%x", jstat);
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
realname = jack_get_client_name(handle->client);
|
||||
/* Display the unique client name allocated to us */
|
||||
if(AOVERBOSE(1))
|
||||
fprintf( stderr, "Registered as JACK client %s.\n"
|
||||
, realname ? realname : "<nil>" );
|
||||
|
||||
/* Just make sure. */
|
||||
ao->rate = jack_get_sample_rate(handle->client);
|
||||
|
||||
/* Check the sample rate is correct*/
|
||||
if (jack_get_sample_rate( handle->client ) != (jack_nframes_t)ao->rate)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("JACK Sample Rate is different to sample rate of file.");
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Register ports with Jack*/
|
||||
if(handle->channels > 0 && handle->channels < 100)
|
||||
{
|
||||
for(i=0;i<handle->channels;++i)
|
||||
{
|
||||
char numbuf[3]; /* two digits, zero byte */
|
||||
sprintf(numbuf, "%d", i+1);
|
||||
if( !(handle->ports[i] = jack_port_register( handle->client
|
||||
, numbuf, JACK_DEFAULT_AUDIO_TYPE
|
||||
, JackPortIsOutput, 0 )) )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Cannot register JACK output port '%s'.", numbuf);
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("excessive number of output channels (%d).", handle->channels);
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Use device_buffer parameter for ring buffer, but ensure that two
|
||||
JACK buffers fit in there. We do not support that buffer increasing
|
||||
later on. */
|
||||
handle->rb_size = (size_t)( ao->device_buffer
|
||||
* jack_get_sample_rate(handle->client)
|
||||
+ 0.5 ); /* PCM frames */
|
||||
handle->procbuf_frames = jack_get_buffer_size(handle->client);
|
||||
if(handle->rb_size < 2*handle->procbuf_frames)
|
||||
handle->rb_size = 2*handle->procbuf_frames;
|
||||
debug1("JACK ringbuffer for %"SIZE_P" PCM frames", (size_p)handle->rb_size);
|
||||
/* Convert to bytes. */
|
||||
handle->rb_size *= handle->framesize;
|
||||
handle->rb = jack_ringbuffer_create(handle->rb_size);
|
||||
handle->procbuf = malloc(handle->procbuf_frames*handle->framesize);
|
||||
if(!handle->rb || !handle->procbuf)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("failed to allocate buffers");
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the callbacks*/
|
||||
jack_set_process_callback(handle->client, process_callback, (void*)handle);
|
||||
jack_on_shutdown(handle->client, shutdown_callback, (void*)handle);
|
||||
handle->alive = 1;
|
||||
/* Activate client*/
|
||||
if(jack_activate(handle->client))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Can't activate client.");
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Connect up the portsm, return */
|
||||
if(!connect_jack_ports(ao, handle))
|
||||
{
|
||||
/* deregistering of ports will not work but should just fail, then,
|
||||
and let the rest clean up */
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("Jack open successful.\n");
|
||||
ao->realname = compat_strdup(realname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Jack prefers floats, I actually assume it does _only_ float/double
|
||||
(as it is nowadays)! */
|
||||
static int get_formats_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
|
||||
if(jack_get_sample_rate(handle->client) != (jack_nframes_t)ao->rate)
|
||||
return 0;
|
||||
else
|
||||
return MPG123_ENC_FLOAT_32|MPG123_ENC_FLOAT_64;
|
||||
}
|
||||
|
||||
static int write_jack(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
size_t bytes_left;
|
||||
unsigned int strike = 0;
|
||||
|
||||
bytes_left = len;
|
||||
while(bytes_left && handle->alive)
|
||||
{
|
||||
size_t piece;
|
||||
|
||||
debug("writing to ringbuffer");
|
||||
/* No help: piece1 = jack_ringbuffer_write_space(handle->rb); */
|
||||
piece = jack_ringbuffer_write(handle->rb, (char*)buf, bytes_left);
|
||||
debug1("wrote %"SIZE_P" B", (size_p)piece);
|
||||
buf += piece;
|
||||
bytes_left -= piece;
|
||||
/* Allow nothing being written some times, but not too often.
|
||||
Don't know how often in a row that would be supposed to happen. */
|
||||
if(!piece)
|
||||
{
|
||||
if(++strike > 100)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Cannot write to ringbuffer.");
|
||||
break;
|
||||
}
|
||||
/* Avoid busy waiting and semaphore accumulation:
|
||||
Wait once on the semaphore, then clear it. We count on it being
|
||||
posted by the process callback and we are going to push new data
|
||||
so that that one gets the chance. */
|
||||
sem_wait(&handle->sem);
|
||||
do errno = 0;
|
||||
while(sem_trywait(&handle->sem) == 0 || errno == EINTR);
|
||||
}
|
||||
else
|
||||
strike = 0;
|
||||
}
|
||||
|
||||
return len-bytes_left;
|
||||
}
|
||||
|
||||
static void flush_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
/* Reset the ring buffers*/
|
||||
jack_ringbuffer_reset(handle->rb);
|
||||
}
|
||||
|
||||
static int init_jack(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL)
|
||||
return -1;
|
||||
/* Set callbacks */
|
||||
ao->open = open_jack;
|
||||
ao->flush = flush_jack;
|
||||
ao->drain = drain_jack;
|
||||
ao->write = write_jack;
|
||||
ao->get_formats = get_formats_jack;
|
||||
ao->close = close_jack;
|
||||
ao->propflags |= OUT123_PROP_PERSISTENT;
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "jack",
|
||||
/* description */ "Output audio using JACK (JACK Audio Connection Kit).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_jack
|
||||
};
|
||||
199
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/mint.c
vendored
Normal file
199
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/mint.c
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
mint: audio output for MINT
|
||||
|
||||
copyright ?-2006 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 Petr Stehlik
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
/* derived from LINUX, VOXWARE and SUN for MiNT Audio Device by Petr Stehlik */
|
||||
#include <fcntl.h>
|
||||
#include <ioctl.h>
|
||||
#include <audios.h>
|
||||
#include "debug.h"
|
||||
|
||||
/* Globals */
|
||||
extern int outburst;
|
||||
int real_rate_printed = 0;
|
||||
|
||||
|
||||
|
||||
static int rate_best_match(out123_handle *ao)
|
||||
{
|
||||
int ret,dsp_rate;
|
||||
|
||||
if(!ai || ao->fn < 0 || ao->rate < 0)
|
||||
return -1;
|
||||
|
||||
dsp_rate = ao->rate;
|
||||
ret = ioctl(ao->fn,AIOCSSPEED, (void *)dsp_rate);
|
||||
ret = ioctl(ao->fn,AIOCGSPEED,&dsp_rate);
|
||||
if(ret < 0) return ret;
|
||||
ao->rate = dsp_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_rate(out123_handle *ao)
|
||||
{
|
||||
int dsp_rate = ao->rate;
|
||||
|
||||
if(ao->rate >= 0) {
|
||||
int ret, real_rate;
|
||||
ret = ioctl(ao->fn, AIOCSSPEED, (void *)dsp_rate);
|
||||
if (ret >= 0 && !real_rate_printed) {
|
||||
ioctl(ao->fn,AIOCGSPEED,&real_rate);
|
||||
if (real_rate != dsp_rate) {
|
||||
fprintf(stderr, "Replay rate: %d Hz\n", real_rate);
|
||||
real_rate_printed = 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_channels(out123_handle *ao)
|
||||
{
|
||||
int chan = ao->channels;
|
||||
|
||||
if(ao->channels < 1) return 0;
|
||||
|
||||
return ioctl(ao->fn, AIOCSCHAN, (void *)chan);
|
||||
}
|
||||
|
||||
static int set_format(out123_handle *ao)
|
||||
{
|
||||
int fmts;
|
||||
|
||||
if(ao->format == -1)
|
||||
return 0;
|
||||
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
fmts = AFMT_S16;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
fmts = AFMT_U8;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
fmts = AFMT_S8;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
fmts = AFMT_ULAW;
|
||||
break;
|
||||
}
|
||||
|
||||
return ioctl(ao->fn, AIOCSFMT, (void *)fmts);
|
||||
}
|
||||
|
||||
static int reset_parameters(out123_handle *ao)
|
||||
{
|
||||
int ret;
|
||||
ret = ioctl(ao->fn,AIOCRESET,NULL);
|
||||
if(ret >= 0) ret = set_format(ai);
|
||||
if(ret >= 0) ret = set_channels(ai);
|
||||
if(ret >= 0) ret = set_rate(ai);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int open_mint(out123_handle *ao)
|
||||
{
|
||||
const char *dev = ao->device;
|
||||
|
||||
if(!ai) return -1;
|
||||
if(!dev)
|
||||
dev = "/dev/audio";
|
||||
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
|
||||
if(ao->fn < 0)
|
||||
{
|
||||
error1("Can't open %s!",dev);
|
||||
return -1;
|
||||
}
|
||||
ioctl(ao->fn, AIOCGBLKSIZE, &outburst);
|
||||
if(outburst > MAXOUTBURST)
|
||||
outburst = MAXOUTBURST;
|
||||
if(audio_reset_parameters(ai) < 0) {
|
||||
close(ao->fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
static int get_formats_mint(out123_handle *ao)
|
||||
{
|
||||
int ret = 0;
|
||||
int fmts;
|
||||
|
||||
if(ioctl(ao->fn,AIOCGFMTS,&fmts) < 0)
|
||||
return -1;
|
||||
|
||||
if(fmts & AFMT_ULAW)
|
||||
ret |= MPG123_ENC_ULAW_8;
|
||||
if(fmts & AFMT_S16)
|
||||
ret |= MPG123_ENC_SIGNED_16;
|
||||
if(fmts & AFMT_U8)
|
||||
ret |= MPG123_ENC_UNSIGNED_8;
|
||||
if(fmts & AFMT_S8)
|
||||
ret |= MPG123_ENC_SIGNED_8;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_mint(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_mint(out123_handle *ao)
|
||||
{
|
||||
close (ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_mint(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int init_mint(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_mint;
|
||||
ao->flush = flush_mint;
|
||||
ao->write = write_mint;
|
||||
ao->get_formats = get_formats_mint;
|
||||
ao->close = close_mint;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "mint",
|
||||
/* description */ "Audio output for MINT.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_mint,
|
||||
};
|
||||
|
||||
|
||||
345
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/nas.c
vendored
Normal file
345
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/nas.c
vendored
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
nas: audio output via NAS
|
||||
|
||||
copyright ?-2016 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 Martin Denn
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <fcntl.h>
|
||||
#include <audio/audiolib.h>
|
||||
#include <audio/soundlib.h>
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AuServer *aud;
|
||||
AuFlowID flow;
|
||||
AuDeviceAttributes *da;
|
||||
int numDevices;
|
||||
char *buf;
|
||||
AuUint32 buf_size;
|
||||
AuUint32 buf_cnt;
|
||||
AuBool data_sent;
|
||||
AuBool finished;
|
||||
} InfoRec, *InfoPtr;
|
||||
|
||||
/* seconds */
|
||||
#define NAS_SOUND_PORT_DURATION (ao->device_buffer > 0. ? ao->device_buffer : 5)
|
||||
#define NAS_SOUND_LOW_WATER_MARK 25 /* percent */
|
||||
#define NAS_MAX_FORMAT 10 /* currently, there are 7 supported formats */
|
||||
|
||||
|
||||
/* FIXME: stick this inside userptr inside out123_handle instead */
|
||||
static InfoRec info;
|
||||
|
||||
/* NAS specific routines */
|
||||
|
||||
static void nas_sendData(AuServer *aud, InfoPtr i, AuUint32 numBytes)
|
||||
{
|
||||
if (numBytes < i->buf_cnt) {
|
||||
AuWriteElement(aud, i->flow, 0, numBytes, i->buf, AuFalse, NULL);
|
||||
memmove(i->buf, i->buf + numBytes, i->buf_cnt - numBytes);
|
||||
i->buf_cnt = i->buf_cnt - numBytes;
|
||||
}
|
||||
else {
|
||||
AuWriteElement(aud, i->flow, 0, i->buf_cnt, i->buf,
|
||||
(numBytes > i->buf_cnt), NULL);
|
||||
i->buf_cnt = 0;
|
||||
}
|
||||
i->data_sent = AuTrue;
|
||||
}
|
||||
|
||||
static AuBool nas_eventHandler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *handler)
|
||||
{
|
||||
InfoPtr i = (InfoPtr) handler->data;
|
||||
|
||||
switch (ev->type)
|
||||
{
|
||||
case AuEventTypeMonitorNotify:
|
||||
i->finished = AuTrue;
|
||||
break;
|
||||
case AuEventTypeElementNotify:
|
||||
{
|
||||
AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
|
||||
|
||||
switch (event->kind)
|
||||
{
|
||||
case AuElementNotifyKindLowWater:
|
||||
nas_sendData(aud, i, event->num_bytes);
|
||||
break;
|
||||
case AuElementNotifyKindState:
|
||||
switch (event->cur_state)
|
||||
{
|
||||
case AuStatePause:
|
||||
if (event->reason != AuReasonUser)
|
||||
nas_sendData(aud, i, event->num_bytes);
|
||||
break;
|
||||
case AuStateStop:
|
||||
i->finished = AuTrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return AuTrue;
|
||||
}
|
||||
|
||||
/* 0 on error */
|
||||
static int nas_createFlow(out123_handle *ao)
|
||||
{
|
||||
AuDeviceID device = AuNone;
|
||||
AuElement elements[2];
|
||||
unsigned char format;
|
||||
AuUint32 buf_samples;
|
||||
int i;
|
||||
|
||||
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
if (((char) *(short *)"x")=='x') /* ugly, but painless */
|
||||
format = AuFormatLinearSigned16LSB; /* little endian */
|
||||
else
|
||||
format = AuFormatLinearSigned16MSB; /* big endian */
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
format = AuFormatLinearUnsigned8;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
format = AuFormatLinearSigned8;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
format = AuFormatULAW8;
|
||||
break;
|
||||
}
|
||||
/* look for an output device */
|
||||
for (i = 0; i < AuServerNumDevices(info.aud); i++)
|
||||
if (((AuDeviceKind(AuServerDevice(info.aud, i)) ==
|
||||
AuComponentKindPhysicalOutput) &&
|
||||
AuDeviceNumTracks(AuServerDevice(info.aud, i))
|
||||
== ao->channels )) {
|
||||
device = AuDeviceIdentifier(AuServerDevice(info.aud, i));
|
||||
break;
|
||||
}
|
||||
if (device == AuNone) {
|
||||
if(!AOQUIET)
|
||||
error1( "Couldn't find an output device providing %d channels."
|
||||
, ao->channels );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set gain */
|
||||
if(ao->gain >= 0) {
|
||||
info.da = AuGetDeviceAttributes(info.aud, device, NULL);
|
||||
if ((info.da)!=NULL) {
|
||||
AuDeviceGain(info.da) = AuFixedPointFromSum(ao->gain, 0);
|
||||
AuSetDeviceAttributes(info.aud, AuDeviceIdentifier(info.da),
|
||||
AuCompDeviceGainMask, info.da, NULL);
|
||||
}
|
||||
else if(!AOQUIET)
|
||||
error("audio/gain: setable Volume/PCM-Level not supported");
|
||||
}
|
||||
|
||||
if (!(info.flow = AuCreateFlow(info.aud, NULL))) {
|
||||
if(!AOQUIET)
|
||||
error("Couldn't create flow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf_samples = ao->rate * NAS_SOUND_PORT_DURATION;
|
||||
|
||||
AuMakeElementImportClient(&elements[0], /* element */
|
||||
(unsigned short) ao->rate,
|
||||
/* rate */
|
||||
format, /* format */
|
||||
ao->channels, /* channels */
|
||||
AuTrue, /* ??? */
|
||||
buf_samples, /* max samples */
|
||||
(AuUint32) (buf_samples / 100
|
||||
* NAS_SOUND_LOW_WATER_MARK),
|
||||
/* low water mark */
|
||||
0, /* num actions */
|
||||
NULL); /* actions */
|
||||
AuMakeElementExportDevice(&elements[1], /* element */
|
||||
0, /* input */
|
||||
device, /* device */
|
||||
(unsigned short) ao->rate,
|
||||
/* rate */
|
||||
AuUnlimitedSamples, /* num samples */
|
||||
0, /* num actions */
|
||||
NULL); /* actions */
|
||||
AuSetElements(info.aud, /* Au server */
|
||||
info.flow, /* flow ID */
|
||||
AuTrue, /* clocked */
|
||||
2, /* num elements */
|
||||
elements, /* elements */
|
||||
NULL); /* return status */
|
||||
|
||||
AuRegisterEventHandler(info.aud, /* Au server */
|
||||
AuEventHandlerIDMask, /* value mask */
|
||||
0, /* type */
|
||||
info.flow, /* id */
|
||||
nas_eventHandler, /* callback */
|
||||
(AuPointer) &info); /* data */
|
||||
|
||||
info.buf_size = buf_samples * ao->channels * AuSizeofFormat(format);
|
||||
info.buf = (char *) malloc(info.buf_size);
|
||||
if (info.buf == NULL) {
|
||||
if(!AOQUIET)
|
||||
error1("Unable to allocate input/output buffer of size %ld",
|
||||
(long)info.buf_size);
|
||||
return 0;
|
||||
}
|
||||
info.buf_cnt = 0;
|
||||
info.data_sent = AuFalse;
|
||||
info.finished = AuFalse;
|
||||
|
||||
AuStartFlow(info.aud, /* Au server */
|
||||
info.flow, /* id */
|
||||
NULL); /* status */
|
||||
return 1; /* success */
|
||||
}
|
||||
|
||||
|
||||
static void flush_nas(out123_handle *ao)
|
||||
{
|
||||
AuEvent ev;
|
||||
|
||||
while ((!info.data_sent) && (!info.finished)) {
|
||||
AuNextEvent(info.aud, AuTrue, &ev);
|
||||
AuDispatchEvent(info.aud, &ev);
|
||||
}
|
||||
info.data_sent = AuFalse;
|
||||
}
|
||||
|
||||
|
||||
/* returning -1 on error, 0 on success... */
|
||||
static int open_nas(out123_handle *ao)
|
||||
{
|
||||
if(!ao) return -1;
|
||||
|
||||
if (!(info.aud = AuOpenServer(ao->device, 0, NULL, 0, NULL, NULL)))
|
||||
{
|
||||
if (ao->device==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("could not open default NAS server");
|
||||
} else
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("could not open NAS server %s\n", ao->device);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
info.buf_size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_nas(out123_handle *ao)
|
||||
{
|
||||
int i, j, k, ret;
|
||||
|
||||
ret=0;
|
||||
j = AuServerNumFormats(info.aud);
|
||||
for (i=0; i<j; i++) {
|
||||
k=AuServerFormat(info.aud,i);
|
||||
switch (k)
|
||||
{
|
||||
case AuFormatULAW8:
|
||||
ret |= MPG123_ENC_ULAW_8;
|
||||
break;
|
||||
case AuFormatLinearUnsigned8:
|
||||
ret |= MPG123_ENC_UNSIGNED_8;
|
||||
break;
|
||||
case AuFormatLinearSigned8:
|
||||
ret |= MPG123_ENC_SIGNED_8;
|
||||
break;
|
||||
case AuFormatLinearSigned16LSB:
|
||||
ret |= MPG123_ENC_SIGNED_16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_nas(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
int buf_cnt = 0;
|
||||
|
||||
if (info.buf_size == 0)
|
||||
if(!nas_createFlow(ao)) return -1;
|
||||
|
||||
while ((info.buf_cnt + (len - buf_cnt)) > info.buf_size) {
|
||||
memcpy(info.buf + info.buf_cnt,
|
||||
buf + buf_cnt,
|
||||
(info.buf_size - info.buf_cnt));
|
||||
buf_cnt += (info.buf_size - info.buf_cnt);
|
||||
info.buf_cnt += (info.buf_size - info.buf_cnt);
|
||||
flush_nas(ao);
|
||||
}
|
||||
memcpy(info.buf + info.buf_cnt,
|
||||
buf + buf_cnt,
|
||||
(len - buf_cnt));
|
||||
info.buf_cnt += (len - buf_cnt);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_nas(out123_handle *ao)
|
||||
{
|
||||
if (info.aud == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.buf_size == 0) {
|
||||
/* Au server opened, but not yet initialized */
|
||||
AuCloseServer(info.aud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!info.finished) {
|
||||
flush_nas(ao);
|
||||
}
|
||||
AuCloseServer(info.aud);
|
||||
free(info.buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int init_nas(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_nas;
|
||||
ao->flush = flush_nas;
|
||||
ao->write = write_nas;
|
||||
ao->get_formats = get_formats_nas;
|
||||
ao->close = close_nas;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "nas",
|
||||
/* description */ "Output audio using NAS (Network Audio System)",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_nas,
|
||||
};
|
||||
|
||||
|
||||
201
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/openal.c
vendored
Normal file
201
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/openal.c
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
openal.c: audio output on OpenAL
|
||||
|
||||
copyright 1995-2016 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 Taihei Monma
|
||||
*/
|
||||
|
||||
/* Need usleep(). */
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#ifdef OPENAL_SUBDIR_OPENAL
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#elif defined(OPENAL_SUBDIR_AL)
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#else
|
||||
#include <al.h>
|
||||
#include <alc.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define NUM_BUFFERS 16
|
||||
|
||||
#ifndef AL_FORMAT_MONO_FLOAT32
|
||||
#define AL_FORMAT_MONO_FLOAT32 0x10010
|
||||
#endif
|
||||
#ifndef AL_FORMAT_STEREO_FLOAT32
|
||||
#define AL_FORMAT_STEREO_FLOAT32 0x10011
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ALCdevice *device;
|
||||
ALCcontext *context;
|
||||
ALuint source, buffer;
|
||||
ALenum format;
|
||||
ALsizei rate;
|
||||
} mpg123_openal_t;
|
||||
|
||||
|
||||
static int open_openal(out123_handle *ao)
|
||||
{
|
||||
mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
|
||||
|
||||
al->device = alcOpenDevice(NULL);
|
||||
al->context = alcCreateContext(al->device, NULL);
|
||||
alcMakeContextCurrent(al->context);
|
||||
alGenSources(1, &al->source);
|
||||
|
||||
al->rate = ao->rate;
|
||||
if(ao->format == MPG123_ENC_SIGNED_16 && ao->channels == 2) al->format = AL_FORMAT_STEREO16;
|
||||
else if(ao->format == MPG123_ENC_SIGNED_16 && ao->channels == 1) al->format = AL_FORMAT_MONO16;
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8 && ao->channels == 2) al->format = AL_FORMAT_STEREO8;
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8 && ao->channels == 1) al->format = AL_FORMAT_MONO8;
|
||||
else if(ao->format == MPG123_ENC_FLOAT_32 && ao->channels == 2) al->format = AL_FORMAT_STEREO_FLOAT32;
|
||||
else if(ao->format == MPG123_ENC_FLOAT_32 && ao->channels == 1) al->format = AL_FORMAT_MONO_FLOAT32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_formats_openal(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_8|((alIsExtensionPresent((ALubyte*)"AL_EXT_float32") == AL_TRUE) ? MPG123_ENC_FLOAT_32 : 0);
|
||||
}
|
||||
|
||||
static int write_openal(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
ALint state, n;
|
||||
mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
|
||||
|
||||
alGetSourcei(al->source, AL_BUFFERS_QUEUED, &n);
|
||||
if(n < NUM_BUFFERS)
|
||||
{
|
||||
alGenBuffers(1, &al->buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
alGetSourcei(al->source, AL_SOURCE_STATE, &state);
|
||||
if(state != AL_PLAYING)
|
||||
{
|
||||
alSourcePlay(al->source);
|
||||
}
|
||||
while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n == 0)
|
||||
{
|
||||
usleep(10000);
|
||||
}
|
||||
alSourceUnqueueBuffers(al->source, 1, &al->buffer);
|
||||
}
|
||||
|
||||
alBufferData(al->buffer, al->format, buf, len, al->rate);
|
||||
alSourceQueueBuffers(al->source, 1, &al->buffer);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_openal(out123_handle *ao)
|
||||
{
|
||||
ALint state, n;
|
||||
mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
|
||||
|
||||
if (al)
|
||||
{
|
||||
/* wait until all buffers are consumed */
|
||||
while(alGetSourcei(al->source, AL_SOURCE_STATE, &state), state == AL_PLAYING)
|
||||
{
|
||||
usleep(10000);
|
||||
}
|
||||
/* free all processed buffers */
|
||||
while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n > 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(al->source, 1, &al->buffer);
|
||||
alDeleteBuffers(1, &al->buffer);
|
||||
}
|
||||
alDeleteSources(1, &al->source);
|
||||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(al->context);
|
||||
alcCloseDevice(al->device);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_openal(out123_handle *ao)
|
||||
{
|
||||
ALint n;
|
||||
mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
|
||||
|
||||
if (al)
|
||||
{
|
||||
/* stop playing and flush all buffers */
|
||||
alSourceStop(al->source);
|
||||
while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n > 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(al->source, 1, &al->buffer);
|
||||
alDeleteBuffers(1, &al->buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int deinit_openal(out123_handle* ao)
|
||||
{
|
||||
/* Free up memory */
|
||||
if(ao->userptr)
|
||||
{
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_openal(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_openal;
|
||||
ao->flush = flush_openal;
|
||||
ao->write = write_openal;
|
||||
ao->get_formats = get_formats_openal;
|
||||
ao->close = close_openal;
|
||||
ao->deinit = deinit_openal;
|
||||
|
||||
/* Allocate memory for data structure */
|
||||
ao->userptr = malloc( sizeof( mpg123_openal_t ) );
|
||||
if(ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("failed to malloc memory for 'mpg123_openal_t'");
|
||||
return -1;
|
||||
}
|
||||
memset( ao->userptr, 0, sizeof(mpg123_openal_t) );
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "openal",
|
||||
/* description */ "Output audio using OpenAL.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_openal,
|
||||
};
|
||||
|
||||
|
||||
664
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/os2.c
vendored
Normal file
664
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/os2.c
vendored
Normal file
@@ -0,0 +1,664 @@
|
||||
/*
|
||||
os2: OS/2 RealTime DART Engine
|
||||
|
||||
copyright 1998-2006 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 Samuel Audet
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#define INCL_OS2MM
|
||||
#define INCL_DOS
|
||||
#define INCL_VIO
|
||||
#define INCL_KBD
|
||||
#include <os2.h>
|
||||
#include <os2me.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* 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;
|
||||
|
||||
/* audio buffers */
|
||||
static ULONG ulMCIBuffers;
|
||||
|
||||
static MCI_AMP_OPEN_PARMS maop = {0};
|
||||
static MCI_MIXSETUP_PARMS mmp = {0};
|
||||
static MCI_BUFFER_PARMS mbp = {0};
|
||||
static MCI_GENERIC_PARMS mgp = {0};
|
||||
static MCI_SET_PARMS msp = {0};
|
||||
static MCI_STATUS_PARMS mstatp = {0};
|
||||
static MCI_MIX_BUFFER *MixBuffers = NULL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MCI_MIX_BUFFER *NextBuffer;
|
||||
int frameNum;
|
||||
} BUFFERINFO;
|
||||
|
||||
BUFFERINFO *bufferinfo = NULL;
|
||||
|
||||
|
||||
static HEV dataplayed = 0;
|
||||
static ULONG resetcount;
|
||||
static BOOL paused = FALSE;
|
||||
|
||||
static MCI_MIX_BUFFER *tobefilled, *playingbuffer = NULL, playedbuffer;
|
||||
static void *pBufferplayed;
|
||||
|
||||
static BOOL nomoredata,nobuffermode,justflushed;
|
||||
|
||||
static TIB *mainthread; /* thread info to set thread priority */
|
||||
|
||||
ULONG keyboardtid;
|
||||
|
||||
|
||||
static LONG APIENTRY DARTEvent(ULONG ulStatus, MCI_MIX_BUFFER *PlayedBuffer, ULONG ulFlags)
|
||||
{
|
||||
switch(ulFlags)
|
||||
{
|
||||
case MIX_STREAM_ERROR | MIX_WRITE_COMPLETE: /* error occur in device */
|
||||
|
||||
if ( ulStatus == ERROR_DEVICE_UNDERRUN)
|
||||
/* Write buffers to rekick off the amp mixer. */
|
||||
mmp.pmixWrite( mmp.ulMixHandle, MixBuffers, ulMCIBuffers );
|
||||
break;
|
||||
|
||||
case MIX_WRITE_COMPLETE: /* for playback */
|
||||
|
||||
playingbuffer = ((BUFFERINFO *) PlayedBuffer->ulUserParm)->NextBuffer;
|
||||
|
||||
/* the next three lines are only useful to audio_playing_samples() */
|
||||
playedbuffer = *PlayedBuffer;
|
||||
playedbuffer.pBuffer = pBufferplayed;
|
||||
memcpy(playedbuffer.pBuffer, PlayedBuffer->pBuffer, PlayedBuffer->ulBufferLength);
|
||||
|
||||
/* just too bad, the decoder fell behind... here we just keep the
|
||||
buffer to be filled in front of the playing one so that when the
|
||||
decoder kicks back in, we'll hear it in at the right time */
|
||||
if(tobefilled == playingbuffer)
|
||||
{
|
||||
tobefilled = ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer;
|
||||
nomoredata = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
playingframe = ((BUFFERINFO *) playingbuffer->ulUserParm)->frameNum;
|
||||
|
||||
/* if we're about to be short of decoder's data
|
||||
(2nd ahead buffer not filled), let's boost its priority! */
|
||||
if(tobefilled == ( (BUFFERINFO *) ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer)
|
||||
DosSetPriority(PRTYS_THREAD,boostclass,boostdelta,mainthread->tib_ptib2->tib2_ultid);
|
||||
}
|
||||
|
||||
/* empty the played buffer in case it doesn't get filled back */
|
||||
memset(PlayedBuffer->pBuffer,0,PlayedBuffer->ulBufferLength);
|
||||
|
||||
DosPostEventSem(dataplayed);
|
||||
|
||||
mmp.pmixWrite( mmp.ulMixHandle, PlayedBuffer, 1 );
|
||||
break;
|
||||
|
||||
} /* end switch */
|
||||
|
||||
return( TRUE );
|
||||
|
||||
} /* end DARTEvent */
|
||||
|
||||
|
||||
static void MciError(ULONG ulError)
|
||||
{
|
||||
unsigned char buffer[128];
|
||||
ULONG rc;
|
||||
|
||||
rc = mciGetErrorString(ulError, buffer, sizeof(buffer));
|
||||
|
||||
if (rc == MCIERR_SUCCESS)
|
||||
sprintf(mmerror,"MCI Error %d: %s",ULONG_LOWD(ulError),buffer);
|
||||
else
|
||||
sprintf(mmerror,"MCI Error %d: Cannot query error message.",ULONG_LOWD(rc));
|
||||
|
||||
error1("%s",mmerror);
|
||||
}
|
||||
|
||||
|
||||
static int set_volume(out123_handle *ao, USHORT setvolume)
|
||||
{
|
||||
if(setvolume > 100) setvolume = 100;
|
||||
volume = setvolume; /* useful when device is closed and reopened */
|
||||
|
||||
if(maop.usDeviceID)
|
||||
{
|
||||
memset(&msp,0,sizeof(msp));
|
||||
msp.ulAudio = MCI_SET_AUDIO_ALL;
|
||||
msp.ulLevel = setvolume;
|
||||
|
||||
mciSendCommand(maop.usDeviceID, MCI_SET,
|
||||
MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
|
||||
&msp, 0);
|
||||
}
|
||||
return setvolume;
|
||||
}
|
||||
|
||||
|
||||
int open_os2(out123_handle *ao)
|
||||
{
|
||||
ULONG rc,i;
|
||||
char *temp;
|
||||
ULONG openflags;
|
||||
PPIB ppib;
|
||||
USHORT bits;
|
||||
const char *dev = ao->device;
|
||||
|
||||
if(maop.usDeviceID) return (maop.usDeviceID);
|
||||
|
||||
if(!ao) return -1;
|
||||
|
||||
if(!dev) dev = "0";
|
||||
|
||||
if(ao->rate < 0) ao->rate = 44100;
|
||||
if(ao->channels < 0) ao->channels = 2;
|
||||
if(ao->format < 0) ao->format = MPG123_ENC_SIGNED_16;
|
||||
|
||||
if(ao->format == MPG123_ENC_SIGNED_16)
|
||||
bits = 16;
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8)
|
||||
bits = 8;
|
||||
else return -1;
|
||||
|
||||
/* open the mixer device */
|
||||
memset (&maop, 0, sizeof(maop));
|
||||
maop.usDeviceID = 0;
|
||||
maop.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, atoi(dev));
|
||||
|
||||
openflags = MCI_WAIT | MCI_OPEN_TYPE_ID;
|
||||
if(!lockdevice) openflags |= MCI_OPEN_SHAREABLE;
|
||||
|
||||
rc = mciSendCommand(0, MCI_OPEN, openflags, &maop, 0);
|
||||
|
||||
if (ULONG_LOWD(rc) != MCIERR_SUCCESS)
|
||||
{
|
||||
MciError(rc);
|
||||
maop.usDeviceID = 0;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* volume in ao->gain ?? */
|
||||
|
||||
/* Set the MCI_MIXSETUP_PARMS data structure to match the audio stream. */
|
||||
|
||||
memset(&mmp, 0, sizeof(mmp));
|
||||
|
||||
mmp.ulBitsPerSample = bits;
|
||||
mmp.ulFormatTag = MCI_WAVE_FORMAT_PCM;
|
||||
mmp.ulSamplesPerSec = ao->rate;
|
||||
mmp.ulChannels = ao->channels;
|
||||
|
||||
/* Setup the mixer for playback of wave data */
|
||||
mmp.ulFormatMode = MCI_PLAY;
|
||||
mmp.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
|
||||
mmp.pmixEvent = DARTEvent;
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_INIT,
|
||||
&mmp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
maop.usDeviceID = 0;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
volume = set_volume(ao,volume);
|
||||
|
||||
/* Set up the BufferParms data structure and allocate
|
||||
* device buffers from the Amp-Mixer */
|
||||
|
||||
memset(&mbp, 0, sizeof(mbp));
|
||||
free(MixBuffers);
|
||||
free(bufferinfo);
|
||||
if(numbuffers < 5) numbuffers = 5;
|
||||
if(numbuffers > 200) numbuffers = 200;
|
||||
MixBuffers = calloc(numbuffers, sizeof(*MixBuffers));
|
||||
bufferinfo = calloc(numbuffers, sizeof(*bufferinfo));
|
||||
|
||||
ulMCIBuffers = numbuffers;
|
||||
mbp.ulNumBuffers = ulMCIBuffers;
|
||||
/* mbp.ulBufferSize = mmp.ulBufferSize; */
|
||||
/* I don't like this... they must be smaller than 64KB or else the
|
||||
engine needs major rewrite */
|
||||
mbp.ulBufferSize = audiobufsize;
|
||||
mbp.pBufList = MixBuffers;
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_BUFFER,
|
||||
MCI_WAIT | MCI_ALLOCATE_MEMORY,
|
||||
(PVOID) &mbp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
maop.usDeviceID = 0;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
pBufferplayed = playedbuffer.pBuffer = calloc(1,audiobufsize);
|
||||
|
||||
ulMCIBuffers = mbp.ulNumBuffers; /* never know! */
|
||||
|
||||
/* Fill all device buffers with zeros and set linked list */
|
||||
|
||||
for(i = 0; i < ulMCIBuffers; i++)
|
||||
{
|
||||
MixBuffers[i].ulFlags = 0;
|
||||
MixBuffers[i].ulBufferLength = mbp.ulBufferSize;
|
||||
memset(MixBuffers[i].pBuffer, 0, MixBuffers[i].ulBufferLength);
|
||||
|
||||
MixBuffers[i].ulUserParm = (ULONG) &bufferinfo[i];
|
||||
bufferinfo[i].NextBuffer = &MixBuffers[i+1];
|
||||
}
|
||||
|
||||
bufferinfo[i-1].NextBuffer = &MixBuffers[0];
|
||||
|
||||
/* Create a semaphore to know when data has been played by the DART thread */
|
||||
DosCreateEventSem(NULL,&dataplayed,0,FALSE);
|
||||
|
||||
playingbuffer = &MixBuffers[0];
|
||||
tobefilled = &MixBuffers[1];
|
||||
playingframe = 0;
|
||||
nomoredata = TRUE;
|
||||
nobuffermode = FALSE;
|
||||
justflushed = FALSE;
|
||||
|
||||
if(boostprio)
|
||||
{
|
||||
temp = alloca(strlen(boostprio)+1);
|
||||
strcpy(temp,boostprio);
|
||||
|
||||
boostdelta = atoi(temp+1);
|
||||
*(temp+1) = 0;
|
||||
boostclass = atoi(temp);
|
||||
}
|
||||
if(boostclass > 4) boostdelta = 3;
|
||||
if(boostdelta > 31) boostdelta = 31;
|
||||
if(boostdelta < -31) boostdelta = -31;
|
||||
|
||||
|
||||
if(normalprio)
|
||||
{
|
||||
temp = alloca(strlen(normalprio)+1);
|
||||
strcpy(temp,normalprio);
|
||||
|
||||
normaldelta = atoi(temp+1);
|
||||
*(temp+1) = 0;
|
||||
normalclass = atoi(temp);
|
||||
}
|
||||
if(normalclass > 4) normaldelta = 3;
|
||||
if(normaldelta > 31) normaldelta = 31;
|
||||
if(normaldelta < -31) normaldelta = -31;
|
||||
|
||||
|
||||
DosGetInfoBlocks(&mainthread,&ppib); /* ppib not needed, but makes some DOSCALLS.DLL crash */
|
||||
DosSetPriority(PRTYS_THREAD,boostclass,boostdelta,mainthread->tib_ptib2->tib2_ultid);
|
||||
|
||||
/* Write buffers to kick off the amp mixer. see DARTEvent() */
|
||||
rc = mmp.pmixWrite( mmp.ulMixHandle,
|
||||
MixBuffers,
|
||||
ulMCIBuffers );
|
||||
|
||||
return maop.usDeviceID;
|
||||
}
|
||||
|
||||
|
||||
static int write_os2(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
/* if we're too quick, let's wait */
|
||||
if(nobuffermode)
|
||||
{
|
||||
MCI_MIX_BUFFER *temp = playingbuffer;
|
||||
|
||||
while(
|
||||
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) &&
|
||||
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) &&
|
||||
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) )
|
||||
{
|
||||
DosResetEventSem(dataplayed,&resetcount);
|
||||
DosWaitEventSem(dataplayed, -1);
|
||||
temp = playingbuffer;
|
||||
}
|
||||
|
||||
} else {
|
||||
while(tobefilled == playingbuffer)
|
||||
{
|
||||
DosResetEventSem(dataplayed,&resetcount);
|
||||
DosWaitEventSem(dataplayed, -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (justflushed) {
|
||||
justflushed = FALSE;
|
||||
} else {
|
||||
nomoredata = FALSE;
|
||||
|
||||
memcpy(tobefilled->pBuffer, buf, len);
|
||||
tobefilled->ulBufferLength = len;
|
||||
// ((BUFFERINFO *) tobefilled->ulUserParm)->frameNum = fr->frameNum;
|
||||
|
||||
/* if we're out of the water (3rd ahead buffer filled),
|
||||
let's reduce our priority */
|
||||
if(tobefilled == ( (BUFFERINFO *) ( (BUFFERINFO *) ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer)
|
||||
DosSetPriority(PRTYS_THREAD,normalclass,normaldelta,mainthread->tib_ptib2->tib2_ultid);
|
||||
|
||||
tobefilled = ((BUFFERINFO *) tobefilled->ulUserParm)->NextBuffer;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int write_os2(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
if(len > audiobufsize || !playingbuffer) return -1;
|
||||
|
||||
if(mmp.ulBitsPerSample == 16)
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
else if(mmp.ulBitsPerSample == 8)
|
||||
ao->format = MPG123_ENC_UNSIGNED_8;
|
||||
else return -1;
|
||||
|
||||
ao->rate = mmp.ulSamplesPerSec;
|
||||
ao->channels = mmp.ulChannels;
|
||||
|
||||
if(buf && len)
|
||||
{
|
||||
ULONG rc;
|
||||
int upto;
|
||||
|
||||
mstatp.ulItem = MCI_STATUS_POSITION;
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_STATUS,
|
||||
MCI_STATUS_ITEM | MCI_WAIT,
|
||||
&mstatp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
maop.usDeviceID = 0;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* this is hypocrite...
|
||||
DART returns the value in ulReturn instead of ulValue,
|
||||
also it returns in milliseconds and not MMTIME... arg */
|
||||
|
||||
upto = (mstatp.ulReturn-playedbuffer.ulTime) * mmp.ulSamplesPerSec / 1000;
|
||||
upto *= mmp.ulChannels * (mmp.ulBitsPerSample>>3);
|
||||
|
||||
/* if a timing problem occurs, let's at least not crash */
|
||||
if(upto > playingbuffer->ulBufferLength)
|
||||
upto = playingbuffer->ulBufferLength;
|
||||
|
||||
if(len < upto) {
|
||||
memcpy(buf,(char *) (playingbuffer->pBuffer)+upto-len, len);
|
||||
} else {
|
||||
memcpy(buf,(char *) playedbuffer.pBuffer+playedbuffer.ulBufferLength-(len-upto),len-upto);
|
||||
memcpy(buf+(len-upto),playingbuffer->pBuffer,upto);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
static int audio_nobuffermode(out123_handle *ao, int setnobuffermode)
|
||||
{
|
||||
nobuffermode = setnobuffermode;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int audio_trash_buffers(out123_handle *ao)
|
||||
{
|
||||
int i;
|
||||
|
||||
justflushed = TRUE;
|
||||
|
||||
// Fill all device buffers with zeros
|
||||
for(i = 0; i < ulMCIBuffers; i++)
|
||||
memset(MixBuffers[i].pBuffer, 0, MixBuffers[i].ulBufferLength);
|
||||
|
||||
tobefilled = ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer;
|
||||
nomoredata = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
*/
|
||||
|
||||
static int close_os2(out123_handle *ao)
|
||||
{
|
||||
ULONG rc;
|
||||
|
||||
if(!maop.usDeviceID)
|
||||
return 0;
|
||||
|
||||
while(!nomoredata)
|
||||
{
|
||||
DosResetEventSem(dataplayed,&resetcount);
|
||||
DosWaitEventSem(dataplayed, -1);
|
||||
}
|
||||
|
||||
playingbuffer = NULL;
|
||||
|
||||
DosCloseEventSem(dataplayed);
|
||||
dataplayed = 0;
|
||||
|
||||
free(pBufferplayed);
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_BUFFER,
|
||||
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
|
||||
&mbp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
free(bufferinfo);
|
||||
free(MixBuffers);
|
||||
bufferinfo = NULL;
|
||||
MixBuffers = NULL;
|
||||
|
||||
memset(&mbp, 0, sizeof(mbp));
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_CLOSE,
|
||||
MCI_WAIT ,
|
||||
&mgp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
memset(&maop, 0, sizeof(maop));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get formats for specific channel/rate parameters
|
||||
*/
|
||||
int get_formats_os2(out123_handle *ao)
|
||||
{
|
||||
int fmts = 0;
|
||||
ULONG rc;
|
||||
MCI_MIXSETUP_PARMS mmptemp = {0};
|
||||
|
||||
mmp.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
|
||||
mmp.pmixEvent = DARTEvent;
|
||||
|
||||
mmptemp.ulFormatMode = MCI_PLAY;
|
||||
mmptemp.ulSamplesPerSec = ao->rate;
|
||||
mmptemp.ulChannels = ao->channels;
|
||||
|
||||
mmptemp.ulFormatTag = MCI_WAVE_FORMAT_PCM;
|
||||
mmptemp.ulBitsPerSample = 16;
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
|
||||
&mmptemp,
|
||||
0 );
|
||||
|
||||
if((ULONG_LOWD(rc) == MCIERR_SUCCESS) && (rc != 0x4000)) /* undocumented */
|
||||
fmts = fmts | MPG123_ENC_SIGNED_16;
|
||||
|
||||
mmptemp.ulFormatTag = MCI_WAVE_FORMAT_PCM;
|
||||
mmptemp.ulBitsPerSample = 8;
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
|
||||
&mmptemp,
|
||||
0 );
|
||||
|
||||
if((ULONG_LOWD(rc) == MCIERR_SUCCESS) && (rc != 0x4000)) /* undocumented */
|
||||
fmts = fmts | MPG123_ENC_UNSIGNED_8;
|
||||
|
||||
mmptemp.ulFormatTag = MCI_WAVE_FORMAT_ALAW;
|
||||
mmptemp.ulBitsPerSample = 8;
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
|
||||
&mmptemp,
|
||||
0 );
|
||||
|
||||
if((ULONG_LOWD(rc) == MCIERR_SUCCESS) && (rc != 0x4000)) /* undocumented */
|
||||
fmts = fmts | MPG123_ENC_ALAW_8;
|
||||
|
||||
mmptemp.ulFormatTag = MCI_WAVE_FORMAT_MULAW;
|
||||
mmptemp.ulBitsPerSample = 8;
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
|
||||
&mmptemp,
|
||||
0 );
|
||||
|
||||
if((ULONG_LOWD(rc) == MCIERR_SUCCESS) && (rc != 0x4000)) /* undocumented */
|
||||
fmts = fmts | MPG123_ENC_ULAW_8;
|
||||
|
||||
return fmts;
|
||||
}
|
||||
|
||||
static int get_devices_os2(char *info, int deviceid)
|
||||
{
|
||||
char buffer[128];
|
||||
MCI_SYSINFO_PARMS mip;
|
||||
|
||||
if(deviceid && info)
|
||||
{
|
||||
MCI_SYSINFO_LOGDEVICE mid;
|
||||
|
||||
mip.pszReturn = buffer;
|
||||
mip.ulRetSize = sizeof(buffer);
|
||||
mip.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
|
||||
mip.ulNumber = deviceid;
|
||||
|
||||
mciSendCommand(0,
|
||||
MCI_SYSINFO,
|
||||
MCI_WAIT | MCI_SYSINFO_INSTALLNAME,
|
||||
&mip,
|
||||
0);
|
||||
|
||||
mip.ulItem = MCI_SYSINFO_QUERY_DRIVER;
|
||||
mip.pSysInfoParm = ∣
|
||||
strcpy(mid.szInstallName,buffer);
|
||||
|
||||
mciSendCommand(0,
|
||||
MCI_SYSINFO,
|
||||
MCI_WAIT | MCI_SYSINFO_ITEM,
|
||||
&mip,
|
||||
0);
|
||||
|
||||
strcpy(info,mid.szProductInfo);
|
||||
return deviceid;
|
||||
|
||||
} else {
|
||||
int number;
|
||||
|
||||
mip.pszReturn = buffer;
|
||||
mip.ulRetSize = sizeof(buffer);
|
||||
mip.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
|
||||
|
||||
mciSendCommand(0,
|
||||
MCI_SYSINFO,
|
||||
MCI_WAIT | MCI_SYSINFO_QUANTITY,
|
||||
&mip,
|
||||
0);
|
||||
|
||||
number = atoi(mip.pszReturn);
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void flush_os2(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int init_os2(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_os2;
|
||||
ao->flush = flush_os2;
|
||||
ao->write = write_os2;
|
||||
ao->get_formats = get_formats_os2;
|
||||
ao->close = close_os2;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "os2",
|
||||
/* description */ "Audio output for OS2.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_os2,
|
||||
};
|
||||
|
||||
|
||||
321
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/oss.c
vendored
Normal file
321
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/oss.c
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
oss: audio output via Open Sound System
|
||||
|
||||
copyright ?-2006 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
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_LINUX_SOUNDCARD_H
|
||||
#include <linux/soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOUNDCARD_H
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MACHINE_SOUNDCARD_H
|
||||
#include <machine/soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifndef AFMT_S16_NE
|
||||
# ifdef OSS_BIG_ENDIAN
|
||||
# define AFMT_S16_NE AFMT_S16_BE
|
||||
# else
|
||||
# define AFMT_S16_NE AFMT_S16_LE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef AFMT_U16_NE
|
||||
# ifdef OSS_BIG_ENDIAN
|
||||
# define AFMT_U16_NE AFMT_U16_BE
|
||||
# else
|
||||
# define AFMT_U16_NE AFMT_U16_LE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
struct oss_stuff
|
||||
{
|
||||
int fragment; /* size of one fragment */
|
||||
int nfrag; /* number of fragments */
|
||||
};
|
||||
|
||||
static int rate_best_match_oss(out123_handle *ao)
|
||||
{
|
||||
int ret,dsp_rate;
|
||||
|
||||
if(!ao || ao->fn < 0 || ao->rate < 0) return -1;
|
||||
dsp_rate = ao->rate;
|
||||
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_SPEED,&dsp_rate);
|
||||
if(ret < 0) return ret;
|
||||
ao->rate = dsp_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_rate_oss(out123_handle *ao)
|
||||
{
|
||||
int dsp_rate;
|
||||
int ret = 0;
|
||||
|
||||
if(ao->rate >= 0) {
|
||||
dsp_rate = ao->rate;
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_SPEED,&dsp_rate);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_channels_oss(out123_handle *ao)
|
||||
{
|
||||
int chan = ao->channels - 1;
|
||||
int ret;
|
||||
|
||||
if(ao->channels < 0) return 0;
|
||||
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_STEREO, &chan);
|
||||
if(chan != (ao->channels-1)) return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_format_oss(out123_handle *ao)
|
||||
{
|
||||
int fmts;
|
||||
int sf,ret;
|
||||
|
||||
if(ao->format == -1) return 0;
|
||||
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
fmts = AFMT_S16_NE;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
fmts = AFMT_U8;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
fmts = AFMT_S8;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
fmts = AFMT_MU_LAW;
|
||||
break;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
fmts = AFMT_A_LAW;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_16:
|
||||
fmts = AFMT_U16_NE;
|
||||
break;
|
||||
}
|
||||
|
||||
sf = fmts;
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_SETFMT, &fmts);
|
||||
if(sf != fmts) return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int reset_parameters_oss(out123_handle *ao)
|
||||
{
|
||||
int ret;
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_RESET, NULL);
|
||||
if(ret < 0 && !AOQUIET) error("Can't reset audio!");
|
||||
ret = set_format_oss(ao);
|
||||
if (ret == -1) goto err;
|
||||
ret = set_channels_oss(ao);
|
||||
if (ret == -1) goto err;
|
||||
ret = set_rate_oss(ao);
|
||||
if (ret == -1) goto err;
|
||||
|
||||
/* Careful here. As per OSS v1.1, the next ioctl() commits the format
|
||||
* set above, so we must issue SNDCTL_DSP_RESET before we're allowed to
|
||||
* change it again. [dk]
|
||||
*/
|
||||
|
||||
/* FIXME: this needs re-enabled (but not using global variables this time):
|
||||
if (ioctl(ao->fn, SNDCTL_DSP_GETBLKSIZE, &outburst) == -1 ||
|
||||
outburst > MAXOUTBURST)
|
||||
outburst = MAXOUTBURST;
|
||||
*/
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int open_oss(out123_handle *ao)
|
||||
{
|
||||
char usingdefdev = 0;
|
||||
const char *dev;
|
||||
|
||||
if(!ao) return -1;
|
||||
|
||||
dev = ao->device;
|
||||
if(!dev) {
|
||||
dev = "/dev/dsp";
|
||||
usingdefdev = 1;
|
||||
}
|
||||
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
|
||||
if(ao->fn < 0)
|
||||
{
|
||||
if(usingdefdev) {
|
||||
dev = "/dev/sound/dsp";
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
if(ao->fn < 0) {
|
||||
if(!AOQUIET) error("Can't open default sound device!");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if(!AOQUIET) error1("Can't open %s!",dev);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(reset_parameters_oss(ao) < 0) {
|
||||
close(ao->fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ao->gain >= 0) {
|
||||
int e,mask;
|
||||
e = ioctl(ao->fn , SOUND_MIXER_READ_DEVMASK ,&mask);
|
||||
if(e < 0) {
|
||||
if(!AOQUIET) error("audio/gain: Can't get audio device features list.");
|
||||
}
|
||||
else if(mask & SOUND_MASK_PCM) {
|
||||
int gain = (ao->gain<<8)|(ao->gain);
|
||||
e = ioctl(ao->fn, SOUND_MIXER_WRITE_PCM , &gain);
|
||||
}
|
||||
else if(!(mask & SOUND_MASK_VOLUME)) {
|
||||
if(!AOQUIET) error1("audio/gain: setable Volume/PCM-Level not supported by your audio device: %#04x",mask);
|
||||
}
|
||||
else {
|
||||
int gain = (ao->gain<<8)|(ao->gain);
|
||||
e = ioctl(ao->fn, SOUND_MIXER_WRITE_VOLUME , &gain);
|
||||
}
|
||||
}
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* get formats for specific channel/rate parameters
|
||||
*/
|
||||
static int get_formats_oss(out123_handle *ao)
|
||||
{
|
||||
int fmt = 0;
|
||||
int r = ao->rate;
|
||||
int c = ao->channels;
|
||||
int i;
|
||||
|
||||
static int fmts[] = {
|
||||
MPG123_ENC_ULAW_8 , MPG123_ENC_SIGNED_16 ,
|
||||
MPG123_ENC_UNSIGNED_8 , MPG123_ENC_SIGNED_8 ,
|
||||
MPG123_ENC_UNSIGNED_16 , MPG123_ENC_ALAW_8
|
||||
};
|
||||
|
||||
/* Reset is required before we're allowed to set the new formats. [dk] */
|
||||
ioctl(ao->fn, SNDCTL_DSP_RESET, NULL);
|
||||
|
||||
for(i=0;i<6;i++) {
|
||||
ao->format = fmts[i];
|
||||
if(set_format_oss(ao) < 0) {
|
||||
continue;
|
||||
}
|
||||
ao->channels = c;
|
||||
if(set_channels_oss(ao) < 0) {
|
||||
continue;
|
||||
}
|
||||
ao->rate = r;
|
||||
if(rate_best_match_oss(ao) < 0) {
|
||||
continue;
|
||||
}
|
||||
if( (ao->rate*100 > r*(100-AUDIO_RATE_TOLERANCE)) && (ao->rate*100 < r*(100+AUDIO_RATE_TOLERANCE)) ) {
|
||||
fmt |= fmts[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
if(ioctl(ao->fn,SNDCTL_DSP_GETFMTS,&fmts) < 0) {
|
||||
if(!AOQUIET) error("Failed to get SNDCTL_DSP_GETFMTS");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(fmts & AFMT_MU_LAW)
|
||||
ret |= MPG123_ENC_ULAW_8;
|
||||
if(fmts & AFMT_S16_NE)
|
||||
ret |= MPG123_ENC_SIGNED_16;
|
||||
if(fmts & AFMT_U8)
|
||||
ret |= MPG123_ENC_UNSIGNED_8;
|
||||
if(fmts & AFMT_S8)
|
||||
ret |= MPG123_ENC_SIGNED_8;
|
||||
if(fmts & AFMT_U16_NE)
|
||||
ret |= MPG123_ENC_UNSIGNED_16;
|
||||
if(fmts & AFMT_A_LAW)
|
||||
ret |= MPG123_ENC_ALAW_8;
|
||||
#endif
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
static int write_oss(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_oss(out123_handle *ao)
|
||||
{
|
||||
close(ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_oss(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int init_oss(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_oss;
|
||||
ao->flush = flush_oss;
|
||||
ao->write = write_oss;
|
||||
ao->get_formats = get_formats_oss;
|
||||
ao->close = close_oss;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "oss",
|
||||
/* description */ "Output audio using OSS",
|
||||
/* revision */ "$Rev: 4021 $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_oss,
|
||||
};
|
||||
|
||||
|
||||
330
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/portaudio.c
vendored
Normal file
330
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/portaudio.c
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
portaudio: audio output via PortAudio cross-platform audio API
|
||||
|
||||
copyright 2006-2016 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 Nicholas J. Humfrey
|
||||
*/
|
||||
|
||||
/* Need usleep(). */
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#include "out123_int.h"
|
||||
#include <math.h>
|
||||
#include <portaudio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Including the sfifo code locally, to avoid module linkage issues. */
|
||||
#define SFIFO_STATIC
|
||||
#include "sfifo.c"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define SAMPLE_SIZE (2)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#define FIFO_DURATION (ao->device_buffer > 0. ? ao->device_buffer : 0.5f)
|
||||
|
||||
|
||||
typedef struct {
|
||||
PaStream *stream;
|
||||
sfifo_t fifo;
|
||||
int finished;
|
||||
} mpg123_portaudio_t;
|
||||
|
||||
#ifdef PORTAUDIO18
|
||||
#define PaTime PaTimestamp
|
||||
#define Pa_IsStreamActive Pa_StreamActive
|
||||
#endif
|
||||
|
||||
/* Some busy waiting. Proper stuff like semaphores might add
|
||||
dependencies (POSIX) that the platform does not know. */
|
||||
static void ms_sleep(int milliseconds)
|
||||
{
|
||||
#ifdef WIN32
|
||||
Sleep(milliseconds);
|
||||
#else
|
||||
usleep(milliseconds*1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PORTAUDIO18
|
||||
static int paCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTime outTime, void *userData )
|
||||
#else
|
||||
static int paCallback(
|
||||
const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData )
|
||||
#endif
|
||||
{
|
||||
out123_handle *ao = userData;
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
unsigned long bytes = framesPerBuffer * SAMPLE_SIZE * ao->channels;
|
||||
int bytes_avail;
|
||||
int bytes_read;
|
||||
|
||||
while((bytes_avail=sfifo_used(&pa->fifo))<bytes && !pa->finished)
|
||||
{
|
||||
int ms = (bytes-bytes_avail)/ao->framesize*1000/ao->rate;
|
||||
debug3("waiting for more input, %d ms missing (%i < %lu)"
|
||||
, ms, bytes_avail, bytes);
|
||||
ms_sleep(ms/10);
|
||||
}
|
||||
if(bytes_avail > bytes)
|
||||
bytes_avail = bytes;
|
||||
bytes_read = sfifo_read(&pa->fifo, outputBuffer, bytes_avail);
|
||||
if(bytes_read != bytes_avail)
|
||||
warning2("Error reading from the FIFO (wanted=%d, bytes_read=%d).\n"
|
||||
, bytes_avail, bytes_read);
|
||||
if(bytes_read < 0)
|
||||
bytes_read = 0;
|
||||
/* Ensure that any remaining space is filled with zero bytes. */
|
||||
if(bytes_read >= 0 && bytes_read < bytes)
|
||||
memset((char*)outputBuffer+bytes_read, 0, bytes-bytes_read);
|
||||
|
||||
debug1("callback successfully passed along %i B", bytes_read);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int open_portaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
PaError err;
|
||||
|
||||
pa->finished = 0;
|
||||
/* Open an audio I/O stream. */
|
||||
if (ao->rate > 0 && ao->channels >0 ) {
|
||||
|
||||
err = Pa_OpenDefaultStream(
|
||||
&pa->stream,
|
||||
0, /* no input channels */
|
||||
ao->channels, /* number of output channels */
|
||||
paInt16, /* signed 16-bit samples */
|
||||
ao->rate, /* sample rate */
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
#ifdef PORTAUDIO18
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
#endif
|
||||
paCallback, /* no callback - use blocking IO */
|
||||
ao );
|
||||
|
||||
if( err != paNoError ) {
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to open PortAudio default stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialise FIFO */
|
||||
sfifo_init( &pa->fifo, ao->rate * FIFO_DURATION * SAMPLE_SIZE *ao->channels );
|
||||
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_portaudio(out123_handle *ao)
|
||||
{
|
||||
/* Only implemented Signed 16-bit audio for now */
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
|
||||
static int write_portaudio(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
PaError err;
|
||||
int len_remain = len;
|
||||
|
||||
/* Some busy waiting, but feed what is possible. */
|
||||
while(len_remain) /* Note: input len is multiple of framesize! */
|
||||
{
|
||||
int block = sfifo_space(&pa->fifo);
|
||||
block -= block % ao->framesize;
|
||||
debug1("space for writing: %i", block);
|
||||
if(block > len_remain)
|
||||
block = len_remain;
|
||||
if(block)
|
||||
{
|
||||
sfifo_write(&pa->fifo, buf, block);
|
||||
len_remain -= block;
|
||||
buf += block;
|
||||
/* Start stream if not ative and 50 % full.*/
|
||||
if(sfifo_used(&pa->fifo) > (sfifo_size(&pa->fifo)/2))
|
||||
{
|
||||
pa->finished = 0;
|
||||
err = Pa_IsStreamActive( pa->stream );
|
||||
if (err == 0) {
|
||||
err = Pa_StartStream( pa->stream );
|
||||
if( err != paNoError ) {
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to start PortAudio stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1; /* triggering exit here is not good, better handle that somehow... */
|
||||
}
|
||||
else
|
||||
debug("started stream");
|
||||
} else if (err < 0)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to check state of PortAudio stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
debug("stream already active");
|
||||
}
|
||||
}
|
||||
if(len_remain)
|
||||
{
|
||||
debug1("Still need to write %d bytes, sleeping a bit.", len_remain);
|
||||
ms_sleep(0.1*FIFO_DURATION*1000);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_portaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
PaError err;
|
||||
int stuff;
|
||||
|
||||
debug1("close_portaudio with %d", sfifo_used(&pa->fifo));
|
||||
pa->finished = 1;
|
||||
/* Wait at least until the FIFO is empty. */
|
||||
while((stuff = sfifo_used(&pa->fifo))>0)
|
||||
{
|
||||
int ms = stuff/ao->framesize*1000/ao->rate;
|
||||
debug1("still stuff for about %i ms there", ms);
|
||||
ms_sleep(ms/2);
|
||||
}
|
||||
|
||||
if (pa->stream) {
|
||||
/* stop the stream if it is active */
|
||||
if (Pa_IsStreamActive( pa->stream ) == 1) {
|
||||
err = Pa_StopStream( pa->stream );
|
||||
if( err != paNoError )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to stop PortAudio stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* and then close the stream */
|
||||
err = Pa_CloseStream( pa->stream );
|
||||
if( err != paNoError )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to close PortAudio stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
pa->stream = NULL;
|
||||
}
|
||||
|
||||
/* and free memory used by fifo */
|
||||
sfifo_close( &pa->fifo );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void flush_portaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
/*PaError err;*/
|
||||
|
||||
/* throw away contents of FIFO */
|
||||
sfifo_flush( &pa->fifo );
|
||||
|
||||
/* and empty out PortAudio buffers */
|
||||
/*err = */
|
||||
Pa_AbortStream( pa->stream );
|
||||
}
|
||||
|
||||
|
||||
static int deinit_portaudio(out123_handle* ao)
|
||||
{
|
||||
/* Free up memory */
|
||||
if (ao->userptr) {
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Shut down PortAudio */
|
||||
Pa_Terminate();
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_portaudio(out123_handle* ao)
|
||||
{
|
||||
int err = paNoError;
|
||||
mpg123_portaudio_t *handle;
|
||||
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_portaudio;
|
||||
ao->flush = flush_portaudio;
|
||||
ao->write = write_portaudio;
|
||||
ao->get_formats = get_formats_portaudio;
|
||||
ao->close = close_portaudio;
|
||||
ao->deinit = deinit_portaudio;
|
||||
|
||||
/* Initialise PortAudio */
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to initialise PortAudio: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate memory for handle */
|
||||
ao->userptr = handle = malloc( sizeof(mpg123_portaudio_t) );
|
||||
if (ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error( "Failed to allocated memory for driver structure" );
|
||||
return -1;
|
||||
}
|
||||
handle->finished = 0;
|
||||
handle->stream = NULL;
|
||||
memset(&handle->fifo, 0, sizeof(sfifo_t));
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "portaudio",
|
||||
/* description */ "Output audio using PortAudio",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_portaudio,
|
||||
};
|
||||
|
||||
194
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/pulse.c
vendored
Normal file
194
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/pulse.c
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
pulse: audio output using PulseAudio server
|
||||
|
||||
copyright 2006-2016 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 Nicholas J. Humfrey
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static int open_pulse(out123_handle *ao)
|
||||
{
|
||||
int err;
|
||||
pa_simple* pas = NULL;
|
||||
pa_sample_spec ss;
|
||||
/* Check if already open ? */
|
||||
if (ao->userptr) {
|
||||
if(!AOQUIET)
|
||||
error("Pulse audio output is already open.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open an audio I/O stream. */
|
||||
/* When they are < 0, I shall set some default. */
|
||||
if(ao->rate < 0 || ao->format < 0 || ao->channels < 0)
|
||||
{
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
/* Fill out pulse audio's data structure */
|
||||
ss.channels = ao->channels;
|
||||
ss.rate = ao->rate;
|
||||
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ss.format=PA_SAMPLE_S16BE;
|
||||
#else
|
||||
ss.format=PA_SAMPLE_S16LE;
|
||||
#endif
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_24:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ss.format=PA_SAMPLE_S24BE;
|
||||
#else
|
||||
ss.format=PA_SAMPLE_S24LE;
|
||||
#endif
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_32:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ss.format=PA_SAMPLE_S32BE;
|
||||
#else
|
||||
ss.format=PA_SAMPLE_S32LE;
|
||||
#endif
|
||||
break;
|
||||
case MPG123_ENC_FLOAT_32:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ss.format=PA_SAMPLE_FLOAT32BE;
|
||||
#else
|
||||
ss.format=PA_SAMPLE_FLOAT32LE;
|
||||
#endif
|
||||
break;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
ss.format=PA_SAMPLE_ALAW;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
ss.format=PA_SAMPLE_ULAW;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
ss.format=PA_SAMPLE_U8;
|
||||
break;
|
||||
default:
|
||||
if(!AOQUIET)
|
||||
error1("Unsupported audio format: 0x%x", ao->format);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Perform the open */
|
||||
pas = pa_simple_new(
|
||||
NULL, /* Use the default server */
|
||||
ao->name, /* Our application's name */
|
||||
PA_STREAM_PLAYBACK,
|
||||
ao->device, /* Use the default device if NULL */
|
||||
"via out123", /* Description of our stream */
|
||||
&ss, /* Our sample format */
|
||||
NULL, /* Use default channel map */
|
||||
NULL, /* Use default buffering attributes */
|
||||
&err /* Error result code */
|
||||
);
|
||||
|
||||
if(pas == NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Failed to open pulse audio output: %s", pa_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Store the pointer */
|
||||
ao->userptr = (void*)pas;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_pulse(out123_handle *ao)
|
||||
{
|
||||
/* Only implemented Signed 16-bit audio for now */
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
|
||||
static int write_pulse(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
pa_simple *pas = (pa_simple*)ao->userptr;
|
||||
int ret, err;
|
||||
/* Doesn't return number of bytes but just success or not. */
|
||||
ret = pa_simple_write( pas, buf, len, &err );
|
||||
if(ret<0)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Failed to write audio: %s", pa_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
return len; /* If successful, everything has been written. */
|
||||
}
|
||||
|
||||
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. */
|
||||
pa_simple_drain(pas, &err);
|
||||
pa_simple_free(pas);
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_pulse(out123_handle *ao)
|
||||
{
|
||||
pa_simple *pas = (pa_simple*)ao->userptr;
|
||||
|
||||
if (pas) {
|
||||
int err;
|
||||
pa_simple_flush( pas, &err );
|
||||
if(err && !AOQUIET)
|
||||
error1("Failed to flush audio: %s", pa_strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int init_pulse(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_pulse;
|
||||
ao->flush = flush_pulse;
|
||||
ao->write = write_pulse;
|
||||
ao->get_formats = get_formats_pulse;
|
||||
ao->close = close_pulse;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "pulse",
|
||||
/* description */ "Output audio using PulseAudio Server",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_pulse,
|
||||
};
|
||||
|
||||
272
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/qsa.c
vendored
Normal file
272
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/qsa.c
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
qsa: sound output with QNX Sound Architecture 0.5.2 API
|
||||
|
||||
copyright 2013 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
|
||||
|
||||
written by Mike Gorchak <mike.gorchak.qnx@gmail.com>
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/asoundlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct _qsa_mp_map
|
||||
{
|
||||
uint32_t qsa_format;
|
||||
int mp_format;
|
||||
} qsa_mp_map_t;
|
||||
|
||||
/* in order best format first */
|
||||
qsa_mp_map_t format_map[]=
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
{SND_PCM_SFMT_FLOAT64_BE, MPG123_ENC_FLOAT_64 },
|
||||
{SND_PCM_SFMT_FLOAT_BE, MPG123_ENC_FLOAT_32 },
|
||||
{SND_PCM_SFMT_S32_BE, MPG123_ENC_SIGNED_32 },
|
||||
{SND_PCM_SFMT_U32_BE, MPG123_ENC_UNSIGNED_32 },
|
||||
{SND_PCM_SFMT_S24_BE, MPG123_ENC_SIGNED_24 },
|
||||
{SND_PCM_SFMT_U24_BE, MPG123_ENC_UNSIGNED_24 },
|
||||
{SND_PCM_SFMT_S16_BE, MPG123_ENC_SIGNED_16 },
|
||||
{SND_PCM_SFMT_U16_BE, MPG123_ENC_UNSIGNED_16 },
|
||||
#else
|
||||
{SND_PCM_SFMT_FLOAT64_LE, MPG123_ENC_FLOAT_64 },
|
||||
{SND_PCM_SFMT_FLOAT_LE, MPG123_ENC_FLOAT_32 },
|
||||
{SND_PCM_SFMT_S32_LE, MPG123_ENC_SIGNED_32 },
|
||||
{SND_PCM_SFMT_U32_LE, MPG123_ENC_UNSIGNED_32 },
|
||||
{SND_PCM_SFMT_S24_LE, MPG123_ENC_SIGNED_24 },
|
||||
{SND_PCM_SFMT_U24_LE, MPG123_ENC_UNSIGNED_24 },
|
||||
{SND_PCM_SFMT_S16_LE, MPG123_ENC_SIGNED_16 },
|
||||
{SND_PCM_SFMT_U16_LE, MPG123_ENC_UNSIGNED_16 },
|
||||
#endif
|
||||
{SND_PCM_SFMT_U8, MPG123_ENC_UNSIGNED_8 },
|
||||
{SND_PCM_SFMT_S8, MPG123_ENC_SIGNED_8 },
|
||||
{SND_PCM_SFMT_A_LAW, MPG123_ENC_ALAW_8 },
|
||||
{SND_PCM_SFMT_MU_LAW, MPG123_ENC_ULAW_8 },
|
||||
{0, 0 },
|
||||
};
|
||||
|
||||
typedef struct _qsa_internal
|
||||
{
|
||||
int cardno;
|
||||
int deviceno;
|
||||
snd_pcm_t* audio_handle;
|
||||
snd_pcm_channel_params_t cpars;
|
||||
} qsa_internal_t;
|
||||
|
||||
static int open_qsa(out123_handle* ao)
|
||||
{
|
||||
int status;
|
||||
int cardno;
|
||||
int deviceno;
|
||||
int it;
|
||||
snd_pcm_t* audio_handle;
|
||||
qsa_internal_t* userptr;
|
||||
|
||||
ao->userptr=NULL;
|
||||
|
||||
status=snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, SND_PCM_OPEN_PLAYBACK);
|
||||
if (status<0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status=snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP);
|
||||
if (status<0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
userptr=calloc(1, sizeof(qsa_internal_t));
|
||||
if (userptr==NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
ao->userptr=userptr;
|
||||
userptr->audio_handle=audio_handle;
|
||||
userptr->cardno=cardno;
|
||||
userptr->deviceno=deviceno;
|
||||
|
||||
memset(&userptr->cpars, 0, sizeof(userptr->cpars));
|
||||
|
||||
userptr->cpars.channel=SND_PCM_CHANNEL_PLAYBACK;
|
||||
userptr->cpars.mode=SND_PCM_MODE_BLOCK;
|
||||
userptr->cpars.start_mode=SND_PCM_START_DATA;
|
||||
userptr->cpars.stop_mode=SND_PCM_STOP_STOP;
|
||||
userptr->cpars.format.format=0;
|
||||
it=0;
|
||||
do {
|
||||
if ((format_map[it].qsa_format==0) && (format_map[it].mp_format==0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ao->format==format_map[it].mp_format)
|
||||
{
|
||||
userptr->cpars.format.format=format_map[it].qsa_format;
|
||||
break;
|
||||
}
|
||||
it++;
|
||||
} while(1);
|
||||
userptr->cpars.format.interleave=1;
|
||||
userptr->cpars.format.rate=ao->rate;
|
||||
userptr->cpars.format.voices=ao->channels;
|
||||
userptr->cpars.buf.block.frag_size=4096;
|
||||
userptr->cpars.buf.block.frags_min=8;
|
||||
userptr->cpars.buf.block.frags_max=16;
|
||||
|
||||
if ((ao->channels!=-1) && (ao->rate!=-1))
|
||||
{
|
||||
status=snd_pcm_plugin_params(userptr->audio_handle, &userptr->cpars);
|
||||
if (status<0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status=snd_pcm_plugin_prepare(userptr->audio_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (status<0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int get_formats_qsa(out123_handle* ao)
|
||||
{
|
||||
qsa_internal_t* userptr;
|
||||
int status;
|
||||
int it=0;
|
||||
|
||||
userptr=ao->userptr;
|
||||
if (userptr!=NULL);
|
||||
{
|
||||
userptr->cpars.format.rate=ao->rate;
|
||||
userptr->cpars.format.voices=ao->channels;
|
||||
it=0;
|
||||
do {
|
||||
if ((format_map[it].qsa_format==0) && (format_map[it].mp_format==0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
userptr->cpars.format.format=format_map[it].qsa_format;
|
||||
status=snd_pcm_plugin_params(userptr->audio_handle, &userptr->cpars);
|
||||
if (status<0)
|
||||
{
|
||||
it++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return format_map[it].mp_format;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_qsa(out123_handle* ao, unsigned char* buf, int bytes)
|
||||
{
|
||||
int written;
|
||||
int status;
|
||||
snd_pcm_channel_status_t cstatus;
|
||||
qsa_internal_t* userptr;
|
||||
|
||||
userptr=ao->userptr;
|
||||
if (userptr!=NULL);
|
||||
{
|
||||
written=snd_pcm_plugin_write(userptr->audio_handle, buf, bytes);
|
||||
if (written!=bytes)
|
||||
{
|
||||
/* Check if samples playback got stuck somewhere in hardware or in */
|
||||
/* the audio device driver */
|
||||
if ((errno==EAGAIN) && (written==0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((errno==EINVAL) || (errno==EIO))
|
||||
{
|
||||
memset(&cstatus, 0, sizeof(cstatus));
|
||||
cstatus.channel=SND_PCM_CHANNEL_PLAYBACK;
|
||||
status=snd_pcm_plugin_status(userptr->audio_handle, &cstatus);
|
||||
if (status>0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
|
||||
(cstatus.status == SND_PCM_STATUS_READY))
|
||||
{
|
||||
status=snd_pcm_plugin_prepare(userptr->audio_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (status<0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
static void flush_qsa(out123_handle* ao)
|
||||
{
|
||||
qsa_internal_t* userptr;
|
||||
|
||||
userptr=ao->userptr;
|
||||
if (userptr!=NULL);
|
||||
{
|
||||
snd_pcm_playback_flush(userptr->audio_handle);
|
||||
}
|
||||
}
|
||||
|
||||
static int close_qsa(out123_handle* ao)
|
||||
{
|
||||
qsa_internal_t* userptr;
|
||||
|
||||
userptr=ao->userptr;
|
||||
if (userptr!=NULL);
|
||||
{
|
||||
snd_pcm_close(userptr->audio_handle);
|
||||
free(ao->userptr);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int deinit_qsa(out123_handle* ao)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int init_qsa(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_qsa;
|
||||
ao->flush = flush_qsa;
|
||||
ao->write = write_qsa;
|
||||
ao->get_formats = get_formats_qsa;
|
||||
ao->close = close_qsa;
|
||||
ao->deinit = deinit_qsa;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "qsa",
|
||||
/* description */ "Output audio using QNX Sound Architecture (QSA).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
/* init_output */ init_qsa,
|
||||
};
|
||||
302
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sdl.c
vendored
Normal file
302
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sdl.c
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
sdl: audio output via SDL cross-platform API
|
||||
|
||||
copyright 2006-2016 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 Nicholas J. Humfrey
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Including the sfifo code locally, to avoid module linkage issues. */
|
||||
#define SFIFO_STATIC
|
||||
#include "sfifo.c"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#define SAMPLE_SIZE (2)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
/* Performance of SDL with ALSA is a bit of a mystery to me. Regardless
|
||||
of buffer size here, I just cannot avoid buffer underruns on my system.
|
||||
SDL always chooses 1024x2 periods, which seems to be just not quite
|
||||
enough on the Thinkpad:-/ Choosing 0.2 s as a plentiful default instead
|
||||
of 0.5 s which is just a lie. */
|
||||
#define FIFO_DURATION (ao->device_buffer > 0. ? ao->device_buffer : 0.2)
|
||||
#define BUFFER_SAMPLES ((FIFO_DURATION*ao->rate)/2)
|
||||
|
||||
struct handle
|
||||
{
|
||||
int finished; /* A flag for communicating end, one-way. */
|
||||
sfifo_t fifo;
|
||||
};
|
||||
|
||||
/* Some busy waiting. Proper stuff like semaphores might add
|
||||
dependencies (POSIX) that the platform does not know. */
|
||||
static void ms_sleep(int milliseconds)
|
||||
{
|
||||
#ifdef WIN32
|
||||
Sleep(milliseconds);
|
||||
#else
|
||||
usleep(milliseconds*1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The audio function callback takes the following parameters:
|
||||
stream: A pointer to the audio buffer to be filled
|
||||
len: The length (in bytes) of the audio buffer
|
||||
*/
|
||||
static void audio_callback_sdl(void *udata, Uint8 *stream, int len)
|
||||
{
|
||||
out123_handle *ao = (out123_handle*)udata;
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
sfifo_t *fifo = &sh->fifo;
|
||||
int bytes_read;
|
||||
int bytes_avail;
|
||||
|
||||
/* Until the finished flag is set, we will wait for more.
|
||||
As the exact value does not matter and late detection of
|
||||
a change is kindof OK, I do not see a thread safety problem here. */
|
||||
while((bytes_avail = sfifo_used(fifo)) < len && !sh->finished)
|
||||
{
|
||||
int ms = (len-bytes_avail)/ao->framesize*1000/ao->rate;
|
||||
debug1("waiting for more input, %d ms missing", ms);
|
||||
ms_sleep(ms/10);
|
||||
}
|
||||
/* Read audio from FIFO to SDL's buffer */
|
||||
if(bytes_avail > len)
|
||||
bytes_avail = len;
|
||||
bytes_read = sfifo_read( fifo, stream, bytes_avail );
|
||||
if(bytes_read != bytes_avail)
|
||||
warning2("Error reading from the FIFO (wanted=%d, bytes_read=%d).\n"
|
||||
, bytes_avail, bytes_read);
|
||||
if(bytes_read < 0)
|
||||
bytes_read = 0;
|
||||
/* Ensure that any remaining space is filled with zero bytes. */
|
||||
if(bytes_read < len)
|
||||
memset(stream+bytes_read, 0, len-bytes_read);
|
||||
}
|
||||
|
||||
static int open_sdl(out123_handle *ao)
|
||||
{
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
sfifo_t *fifo = &sh->fifo;
|
||||
|
||||
/* Open an audio I/O stream. */
|
||||
if (ao->rate > 0 && ao->channels >0 ) {
|
||||
size_t ringbuffer_len;
|
||||
SDL_AudioSpec wanted;
|
||||
|
||||
/* L16 uncompressed audio data, using 16-bit signed representation in twos
|
||||
complement notation - system endian-ness. */
|
||||
wanted.format = AUDIO_S16SYS;
|
||||
/* Seems reasonable to demand a buffer size related to the device
|
||||
buffer. */
|
||||
wanted.samples = BUFFER_SAMPLES;
|
||||
wanted.callback = audio_callback_sdl;
|
||||
wanted.userdata = ao;
|
||||
wanted.channels = ao->channels;
|
||||
wanted.freq = ao->rate;
|
||||
|
||||
sh->finished = 0;
|
||||
/* Open the audio device, forcing the desired format
|
||||
Actually, it is still subject to constraints by hardware.
|
||||
Need to have sample rate checked beforehand! SDL will
|
||||
happily play 22 kHz files with 44 kHz hardware rate!
|
||||
Same with channel count. No conversion. The manual is a bit
|
||||
misleading on that (only talking about sample format, I guess). */
|
||||
if ( SDL_OpenAudio(&wanted, NULL) )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Couldn't open SDL audio: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialise FIFO */
|
||||
ringbuffer_len = ao->rate * FIFO_DURATION * SAMPLE_SIZE *ao->channels;
|
||||
debug2( "Allocating %d byte ring-buffer (%f seconds)", (int)ringbuffer_len, (float)FIFO_DURATION);
|
||||
if (sfifo_init( fifo, ringbuffer_len ) && !AOQUIET)
|
||||
error1( "Failed to initialise FIFO of size %d bytes", (int)ringbuffer_len );
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_sdl(out123_handle *ao)
|
||||
{
|
||||
/* Got no better idea than to just take 16 bit and run with it */
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
#if 0
|
||||
/*
|
||||
This code would "properly" test audio format support.
|
||||
But thing is, SDL will always say yes and amen to everything, but it takes
|
||||
an awful amount of time to get all the variants tested (about 2 seconds,
|
||||
for example). I have seen SDL builds that do proper format conversion
|
||||
behind your back, I have seen builds that do not. Every build seems to
|
||||
claim that it does, though. Just hope you're lucky and your SDL works.
|
||||
Otherwise, use a proper audio output API.
|
||||
*/
|
||||
SDL_AudioSpec wanted, got;
|
||||
|
||||
/* Only implemented Signed 16-bit audio for now.
|
||||
The SDL manual doesn't suggest more interesting formats
|
||||
like S24 or S32 anyway. */
|
||||
wanted.format = AUDIO_S16SYS;
|
||||
wanted.samples = BUFFER_SAMPLES;
|
||||
wanted.callback = audio_callback_sdl;
|
||||
wanted.userdata = ao;
|
||||
wanted.channels = ao->channels;
|
||||
wanted.freq = ao->rate;
|
||||
|
||||
if(SDL_OpenAudio(&wanted, &got)) return 0;
|
||||
SDL_CloseAudio();
|
||||
fprintf(stderr, "wanted rate: %li got rate %li\n", (long)wanted.freq, (long)got.freq);
|
||||
return (got.freq == ao->rate && got.channels == ao->channels)
|
||||
? MPG123_ENC_SIGNED_16
|
||||
: 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int write_sdl(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
sfifo_t *fifo = &sh->fifo;
|
||||
int len_remain = len;
|
||||
|
||||
/* Some busy waiting, but feed what is possible. */
|
||||
while(len_remain) /* Note: input len is multiple of framesize! */
|
||||
{
|
||||
int block = sfifo_space(fifo);
|
||||
block -= block % ao->framesize;
|
||||
if(block > len_remain)
|
||||
block = len_remain;
|
||||
if(block)
|
||||
{
|
||||
sfifo_write(fifo, buf, block);
|
||||
len_remain -= block;
|
||||
buf += block;
|
||||
/* Unpause once the buffer is 50% full */
|
||||
if (sfifo_used(fifo) > (sfifo_size(fifo)/2) )
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
if(len_remain)
|
||||
{
|
||||
debug1("Still need to write %d bytes, sleeping a bit.", len_remain);
|
||||
ms_sleep(0.1*FIFO_DURATION*1000);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_sdl(out123_handle *ao)
|
||||
{
|
||||
int stuff;
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
sfifo_t *fifo = &sh->fifo;
|
||||
|
||||
debug1("close_sdl with %d", sfifo_used(fifo));
|
||||
sh->finished = 1;
|
||||
/* Wait at least until SDL emptied the FIFO. */
|
||||
while((stuff = sfifo_used(fifo))>0)
|
||||
{
|
||||
int ms = stuff/ao->framesize*1000/ao->rate;
|
||||
debug1("still stuff for about %i ms there", ms);
|
||||
ms_sleep(ms/2);
|
||||
}
|
||||
|
||||
SDL_CloseAudio();
|
||||
|
||||
/* Free up the memory used by the FIFO */
|
||||
sfifo_close( fifo );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_sdl(out123_handle *ao)
|
||||
{
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
|
||||
SDL_PauseAudio(1);
|
||||
sfifo_flush(&sh->fifo);
|
||||
}
|
||||
|
||||
/* You can only rely on that being called after successful init_sdl()!
|
||||
And sdl_close() should be called before to free the sfifo. */
|
||||
static int deinit_sdl(out123_handle* ao)
|
||||
{
|
||||
/* Free up memory */
|
||||
if (ao->userptr) {
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Shut down SDL */
|
||||
SDL_Quit();
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remember: If this returns failure, no additional cleanup happens.
|
||||
Resources must be freed here. */
|
||||
static int init_sdl(out123_handle* ao)
|
||||
{
|
||||
struct handle *sh;
|
||||
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_sdl;
|
||||
ao->flush = flush_sdl;
|
||||
ao->write = write_sdl;
|
||||
ao->get_formats = get_formats_sdl;
|
||||
ao->close = close_sdl;
|
||||
ao->deinit = deinit_sdl;
|
||||
|
||||
/* Initialise SDL */
|
||||
if (SDL_Init( SDL_INIT_AUDIO ) )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Failed to initialise SDL: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
/* Allocate memory _after_ checking that SDL is available, so we do not
|
||||
have to free after failure. */
|
||||
ao->userptr = sh = malloc( sizeof(struct handle) );
|
||||
if (ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error( "Failed to allocated memory for FIFO structure" );
|
||||
return -1;
|
||||
}
|
||||
sh->finished = 0;
|
||||
/* Not exactly necessary; only for somewhat safe sdl_close after a fake
|
||||
sdl_open(). */
|
||||
memset( &sh->fifo, 0, sizeof(sfifo_t) );
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "sdl",
|
||||
/* description */ "Output audio using SDL (Simple DirectMedia Layer).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_sdl,
|
||||
};
|
||||
269
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sgi.c
vendored
Normal file
269
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sgi.c
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
sgi: audio output on SGI boxen
|
||||
|
||||
copyright ?-2013 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 (as it seems) by Thomas Woerner
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <fcntl.h>
|
||||
#include <dmedia/audio.h>
|
||||
#include "errno.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int set_rate(out123_handle *ao, ALconfig config)
|
||||
{
|
||||
int dev = alGetDevice(config);
|
||||
ALpv params[1];
|
||||
|
||||
/* Make sure the device is OK */
|
||||
if(dev < 0)
|
||||
{
|
||||
error1("set_rate: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
if(ao->rate > 0)
|
||||
{
|
||||
params[0].param = AL_RATE;
|
||||
params[0].value.ll = alDoubleToFixed((double)ao->rate);
|
||||
if(alSetParams(dev, params, 1) < 0)
|
||||
{
|
||||
error1("set_rate: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int set_channels(out123_handle *ao, ALconfig config)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(ao->channels == 2)
|
||||
ret = alSetChannels(config, AL_STEREO);
|
||||
else
|
||||
ret = alSetChannels(config, AL_MONO);
|
||||
|
||||
if(ret < 0)
|
||||
{
|
||||
error1("set_channels : %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_format(out123_handle *ao, ALconfig config)
|
||||
{
|
||||
if(ao->format == MPG123_ENC_FLOAT_32)
|
||||
{
|
||||
if(alSetSampFmt(config, AL_SAMPFMT_FLOAT) < 0)
|
||||
{
|
||||
error1("SetSampFmt: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if(alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP) < 0)
|
||||
{
|
||||
error1("SetSampFmt: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
if(alSetWidth(config, AL_SAMPLE_16) < 0)
|
||||
{
|
||||
error1("SetWidth: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int open_sgi(out123_handle *ao)
|
||||
{
|
||||
int current_dev;
|
||||
ALport port = NULL;
|
||||
ALconfig config = alNewConfig();
|
||||
|
||||
ao->userptr = NULL;
|
||||
|
||||
/* Test for correct completion */
|
||||
if(config == 0)
|
||||
{
|
||||
error1("open_sgi: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Setup output device to specified device name. If there is no device name
|
||||
specified in ao structure, use the default for output */
|
||||
if((ao->device) != NULL)
|
||||
{
|
||||
current_dev = alGetResourceByName(AL_SYSTEM, ao->device, AL_OUTPUT_DEVICE_TYPE);
|
||||
|
||||
debug2("Dev: %s %i", ao->device, current_dev);
|
||||
|
||||
if(!current_dev)
|
||||
{
|
||||
int i, numOut;
|
||||
char devname[32];
|
||||
ALpv pv[1];
|
||||
ALvalue *alvalues;
|
||||
|
||||
error2("Invalid audio resource: %s (%s)", ao->device, alGetErrorString(oserror()));
|
||||
|
||||
if((numOut= alQueryValues(AL_SYSTEM,AL_DEFAULT_OUTPUT,0,0,0,0))>=0)
|
||||
fprintf(stderr, "There are %d output devices on this system.\n", numOut);
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Can't find output devices. alQueryValues failed: %s\n", alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
alvalues = malloc(sizeof(ALvalue) * numOut);
|
||||
i = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, alvalues, numOut, pv, 0);
|
||||
if(i == -1)
|
||||
error1("alQueryValues: %s", alGetErrorString(oserror()));
|
||||
else
|
||||
{
|
||||
for(i=0; i < numOut; i++)
|
||||
{
|
||||
pv[0].param = AL_NAME;
|
||||
pv[0].value.ptr = devname;
|
||||
pv[0].sizeIn = 32;
|
||||
alGetParams(alvalues[i].i, pv, 1);
|
||||
|
||||
fprintf(stderr, "%i: %s\n", i, devname);
|
||||
}
|
||||
}
|
||||
free(alvalues);
|
||||
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
if(alSetDevice(config, current_dev) < 0)
|
||||
{
|
||||
error1("open: alSetDevice : %s",alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
} else
|
||||
current_dev = AL_DEFAULT_OUTPUT;
|
||||
|
||||
/* Set the device */
|
||||
if(alSetDevice(config, current_dev) < 0)
|
||||
{
|
||||
error1("open_sgi: %s", alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
/* Set port parameters */
|
||||
|
||||
if(alSetQueueSize(config, 131069) < 0)
|
||||
{
|
||||
error1("open_sgi: setting audio buffer failed: %s", alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
if( set_format(ao, config) < 0
|
||||
|| set_rate(ao, config) < 0
|
||||
|| set_channels(ao, config) < 0 )
|
||||
goto open_sgi_bad;
|
||||
|
||||
/* Open the audio port */
|
||||
port = alOpenPort("mpg123-VSC", "w", config);
|
||||
if(port == NULL)
|
||||
{
|
||||
error1("Unable to open audio channel: %s", alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
ao->userptr = (void*)port;
|
||||
|
||||
alFreeConfig(config);
|
||||
return 1;
|
||||
|
||||
open_sgi_bad:
|
||||
/* clean up and return error */
|
||||
alFreeConfig(config);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_sgi(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_FLOAT_32;
|
||||
}
|
||||
|
||||
|
||||
static int write_sgi(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
int length = len;
|
||||
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
|
||||
ALport port = (ALport)ao->userptr;
|
||||
|
||||
if(ao->channels == 2) length >>= 2;
|
||||
else length >>= 1;
|
||||
|
||||
if(ao->format == MPG123_ENC_FLOAT_32) length >>=1;
|
||||
|
||||
/* Not much error checking ... */
|
||||
alWriteFrames(port, buf, length);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int close_sgi(out123_handle *ao)
|
||||
{
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
|
||||
ALport port = (ALport)ao->userptr;
|
||||
|
||||
if(port)
|
||||
{
|
||||
/* play all remaining samples */
|
||||
while(alGetFilled(port) > 0) sginap(1);
|
||||
|
||||
alClosePort(port);
|
||||
ao->userptr=NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_sgi(out123_handle *ao)
|
||||
{
|
||||
ALport port = (ALport)ao->userptr;
|
||||
|
||||
if(port) alDiscardFrames(port, alGetFilled(port));
|
||||
}
|
||||
|
||||
static int init_sgi(out123_handle* ao)
|
||||
{
|
||||
if(ao == NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_sgi;
|
||||
ao->flush = flush_sgi;
|
||||
ao->write = write_sgi;
|
||||
ao->get_formats = get_formats_sgi;
|
||||
ao->close = close_sgi;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info =
|
||||
{
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "sgi",
|
||||
/* description */ "Audio output for SGI.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_sgi,
|
||||
};
|
||||
161
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sndio.c
vendored
Normal file
161
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sndio.c
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* sndio: sndio audio output
|
||||
*
|
||||
* Copyright (c) 2008 Christian Weisgerber <naddy@openbsd.org>,
|
||||
* Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <sndio.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static int open_sndio(out123_handle *ao)
|
||||
{
|
||||
struct sio_hdl *hdl;
|
||||
struct sio_par par;
|
||||
|
||||
hdl = sio_open(ao->device /* NULL is fine */, SIO_PLAY, 0);
|
||||
if (hdl == NULL)
|
||||
return -1;
|
||||
|
||||
sio_initpar(&par);
|
||||
par.rate = ao->rate;
|
||||
par.pchan = ao->channels;
|
||||
par.le = SIO_LE_NATIVE;
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_32:
|
||||
par.sig = 1;
|
||||
par.bits = 32;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_32:
|
||||
par.sig = 0;
|
||||
par.bits = 32;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
case -1: /* query mode */
|
||||
par.sig = 1;
|
||||
par.bits = 16;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_16:
|
||||
par.sig = 0;
|
||||
par.bits = 16;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
par.sig = 0;
|
||||
par.bits = 8;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
par.sig = 1;
|
||||
par.bits = 8;
|
||||
break;
|
||||
default:
|
||||
if (!AOQUIET)
|
||||
error1("open_sndio: invalid sample format %d",
|
||||
ao->format);
|
||||
sio_close(hdl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par) ||
|
||||
!sio_start(hdl)) {
|
||||
sio_close(hdl);
|
||||
return -1;
|
||||
}
|
||||
if ((par.bits != 8 && par.bits != 16 && par.bits != 32) ||
|
||||
par.le != SIO_LE_NATIVE) {
|
||||
sio_close(hdl);
|
||||
return -1;
|
||||
}
|
||||
ao->rate = par.rate;
|
||||
ao->channels = par.pchan;
|
||||
switch (par.bits) {
|
||||
case 8:
|
||||
ao->format = par.sig ? MPG123_ENC_SIGNED_8 :
|
||||
MPG123_ENC_UNSIGNED_8;
|
||||
break;
|
||||
case 16:
|
||||
ao->format = par.sig ? MPG123_ENC_SIGNED_16 :
|
||||
MPG123_ENC_UNSIGNED_16;
|
||||
break;
|
||||
case 32:
|
||||
ao->format = par.sig ? MPG123_ENC_SIGNED_32 :
|
||||
MPG123_ENC_UNSIGNED_32;
|
||||
break;
|
||||
}
|
||||
ao->userptr = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_formats_sndio(out123_handle *ao)
|
||||
{
|
||||
return (MPG123_ENC_SIGNED_32|MPG123_ENC_UNSIGNED_32|
|
||||
MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_16|
|
||||
MPG123_ENC_UNSIGNED_8|MPG123_ENC_SIGNED_8);
|
||||
}
|
||||
|
||||
static int write_sndio(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
struct sio_hdl *hdl = (struct sio_hdl *)ao->userptr;
|
||||
int count;
|
||||
|
||||
count = (int)sio_write(hdl, buf, len);
|
||||
if (count == 0 && sio_eof(hdl))
|
||||
return -1;
|
||||
return count;
|
||||
}
|
||||
|
||||
static void flush_sndio(out123_handle *ao)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int close_sndio(out123_handle *ao)
|
||||
{
|
||||
struct sio_hdl *hdl = (struct sio_hdl *)ao->userptr;
|
||||
|
||||
sio_close(hdl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_sndio(out123_handle* ao)
|
||||
{
|
||||
if (ao == NULL)
|
||||
return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_sndio;
|
||||
ao->flush = flush_sndio; /* required */
|
||||
ao->write = write_sndio;
|
||||
ao->get_formats = get_formats_sndio;
|
||||
ao->close = close_sndio;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "sndio",
|
||||
/* description */ "Output audio using sndio library",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_sndio,
|
||||
};
|
||||
283
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sun.c
vendored
Normal file
283
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sun.c
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
sun: audio output for Sun systems
|
||||
|
||||
copyright ?-2006 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
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SUN_AUDIOIO_H
|
||||
#include <sun/audioio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_AUDIOIO_H
|
||||
#include <sys/audioio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_AUDIO_H
|
||||
#include <sys/audio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ASM_AUDIOIO_H
|
||||
#include <asm/audioio.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "debug.h"
|
||||
|
||||
static void set_format_helper(out123_handle *ao, audio_info_t *ainfo)
|
||||
{
|
||||
|
||||
switch(ao->format) {
|
||||
case -1:
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
#ifndef AUDIO_ENCODING_LINEAR /* not supported */
|
||||
#define AUDIO_ENCODING_LINEAR 3
|
||||
#endif
|
||||
ainfo->play.encoding = AUDIO_ENCODING_LINEAR;
|
||||
ainfo->play.precision = 16;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
#if defined(SOLARIS) || defined(SPARCLINUX)
|
||||
ainfo->play.encoding = AUDIO_ENCODING_LINEAR8;
|
||||
ainfo->play.precision = 8;
|
||||
break;
|
||||
#endif
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
if(!AOQUIET)
|
||||
error("Linear signed 8 bit not supported!");
|
||||
return;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
ainfo->play.encoding = AUDIO_ENCODING_ULAW;
|
||||
ainfo->play.precision = 8;
|
||||
break;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
ainfo->play.encoding = AUDIO_ENCODING_ALAW;
|
||||
ainfo->play.precision = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int reset_parameters_sun(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
if(ao->rate != -1) ainfo.play.sample_rate = ao->rate;
|
||||
|
||||
if(ao->channels >= 0) ainfo.play.channels = ao->channels;
|
||||
|
||||
set_format_helper(ao,&ainfo);
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rate_best_match(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
|
||||
ainfo.play.sample_rate = ao->rate;
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) < 0) {
|
||||
ao->rate = 0;
|
||||
return 0;
|
||||
}
|
||||
if(ioctl(ao->fn, AUDIO_GETINFO, &ainfo) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ao->rate = ainfo.play.sample_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_rate(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
|
||||
if(ao->rate != -1) {
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
ainfo.play.sample_rate = ao->rate;
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int set_channels(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
ainfo.play.channels = ao->channels;
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_format(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
set_format_helper(ao,&ainfo);
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_sun(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
const char *dev = ao->device;
|
||||
|
||||
if(!dev) {
|
||||
if(getenv("AUDIODEV")) {
|
||||
dev = getenv("AUDIODEV");
|
||||
} else {
|
||||
dev = "/dev/audio";
|
||||
}
|
||||
}
|
||||
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
if(ao->fn < 0) return ao->fn;
|
||||
|
||||
#if defined(SUNOS) && defined(AUDIO_GETDEV)
|
||||
{
|
||||
int type;
|
||||
if(ioctl(ao->fn, AUDIO_GETDEV, &type) == -1) return -1;
|
||||
if(type == AUDIO_DEV_UNKNOWN || type == AUDIO_DEV_AMD)
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
#if defined(SOLARIS) || defined(SPARCLINUX)
|
||||
{
|
||||
struct audio_device ad;
|
||||
if(ioctl(ao->fn, AUDIO_GETDEV, &ad) == -1)
|
||||
return -1;
|
||||
if(!strstr(ad.name,"dbri") && !strstr(ad.name,"CS4231"))
|
||||
warning1("Unknown sound system %s. But we try it.",ad.name);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(reset_parameters_sun(ao) < 0) return -1;
|
||||
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
|
||||
if(ao->flags > 0)
|
||||
ainfo.play.port = 0;
|
||||
if(ao->flags & OUT123_INTERNAL_SPEAKER)
|
||||
ainfo.play.port |= AUDIO_SPEAKER;
|
||||
if(ao->flags & OUT123_HEADPHONES)
|
||||
ainfo.play.port |= AUDIO_HEADPHONE;
|
||||
#ifdef AUDIO_LINE_OUT
|
||||
if(ao->flags & OUT123_LINE_OUT)
|
||||
ainfo.play.port |= AUDIO_LINE_OUT;
|
||||
#endif
|
||||
|
||||
if(ao->gain != -1)
|
||||
ainfo.play.gain = ao->gain;
|
||||
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1)
|
||||
return -1;
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int get_formats_sun(out123_handle *ao)
|
||||
{
|
||||
static int tab[][3] = {
|
||||
{ AUDIO_ENCODING_ULAW , 8, MPG123_ENC_ULAW_8 } ,
|
||||
{ AUDIO_ENCODING_ALAW , 8, MPG123_ENC_ALAW_8 } ,
|
||||
{ AUDIO_ENCODING_LINEAR , 16, MPG123_ENC_SIGNED_16 } ,
|
||||
#if 0
|
||||
#if defined(SOLARIS) || defined(SPARCLINUX)
|
||||
{ AUDIO_ENCODING_LINEAR8 , 8, MPG123_ENC_UNSIGNED_8 } ,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
audio_info_t ainfo;
|
||||
int i,fmts=0;
|
||||
|
||||
for(i=0;i<sizeof(tab)/sizeof(tab[0]);i++) {
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
ainfo.play.encoding = tab[i][0];
|
||||
ainfo.play.precision = tab[i][1];
|
||||
#if 1
|
||||
ainfo.play.sample_rate = ao->rate;
|
||||
ainfo.play.channels = ao->channels;
|
||||
#endif
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) >= 0) {
|
||||
fmts |= tab[i][2];
|
||||
}
|
||||
}
|
||||
return fmts;
|
||||
}
|
||||
|
||||
static int write_sun(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_sun(out123_handle *ao)
|
||||
{
|
||||
close (ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_sun(out123_handle *ao)
|
||||
{
|
||||
/*ioctl (ao->fn, I_FLUSH, FLUSHRW);*/
|
||||
}
|
||||
|
||||
|
||||
static int init_sun(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_sun;
|
||||
ao->flush = flush_sun;
|
||||
ao->write = write_sun;
|
||||
ao->get_formats = get_formats_sun;
|
||||
ao->close = close_sun;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "sun",
|
||||
/* description */ "Audio output for Sun Audio.",
|
||||
/* revision */ "$Rev: 3915 $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_sun,
|
||||
};
|
||||
|
||||
|
||||
213
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/tinyalsa.c
vendored
Normal file
213
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/tinyalsa.c
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
tinyalsa: sound output with TINY Advanced Linux Sound Architecture
|
||||
|
||||
copyright 2006-8 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 Jarno Lehtinen <lehtinen@sci.fi>
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include <tinyalsa/asoundlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct pcm *pcm;
|
||||
struct pcm_params *params;
|
||||
struct pcm_config config;
|
||||
|
||||
unsigned int device;
|
||||
unsigned int card;
|
||||
} mpg123_tinyalsa_t;
|
||||
|
||||
|
||||
static int initialize_device(out123_handle *ao)
|
||||
{
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
ta->config.channels = ao->channels;
|
||||
ta->config.rate = ao->rate;
|
||||
ta->config.period_size = 1024;
|
||||
ta->config.period_count = 4;
|
||||
ta->config.format = PCM_FORMAT_S16_LE;
|
||||
ta->config.start_threshold = 0;
|
||||
ta->config.stop_threshold = 0;
|
||||
ta->config.silence_threshold = 0;
|
||||
|
||||
ta->pcm = pcm_open(ta->card, ta->device, PCM_OUT, &ta->config);
|
||||
if (!ta->pcm || !pcm_is_ready(ta->pcm))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error3( "(open) Unable to open card %u PCM device %u (%s)\n"
|
||||
, ta->card, ta->device, pcm_get_error(ta->pcm) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int open_tinyalsa(out123_handle *ao)
|
||||
{
|
||||
debug("open_tinyalsa()");
|
||||
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
if (ao->format != -1)
|
||||
{
|
||||
/* we're going to play: initalize sample format */
|
||||
return initialize_device(ao);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* query mode; sample format will be set for each query */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_tinyalsa(out123_handle *ao)
|
||||
{
|
||||
debug("get_formats_tinyalsa()");
|
||||
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
if ( ao->rate >= pcm_params_get_min(ta->params, PCM_PARAM_RATE) && ao->rate <= pcm_params_get_max(ta->params, PCM_PARAM_RATE) && ao->channels >= pcm_params_get_min(ta->params, PCM_PARAM_CHANNELS) && ao->channels <= pcm_params_get_max(ta->params, PCM_PARAM_CHANNELS) )
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int write_tinyalsa(out123_handle *ao, unsigned char *buf, int bytes)
|
||||
{
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
if (ta->pcm)
|
||||
{
|
||||
if(pcm_write(ta->pcm, buf, bytes))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Error playing sample\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
static void flush_tinyalsa(out123_handle *ao)
|
||||
{
|
||||
debug("flush_tinyalsa()");
|
||||
}
|
||||
|
||||
|
||||
static int close_tinyalsa(out123_handle *ao)
|
||||
{
|
||||
debug("close_tinyalsa()");
|
||||
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
if (ta->pcm)
|
||||
{
|
||||
pcm_close(ta->pcm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int deinit_tinyalsa(out123_handle* ao)
|
||||
{
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
/* Free up card/device parameters */
|
||||
pcm_params_free(ta->params);
|
||||
|
||||
/* Free up memory */
|
||||
if(ao->userptr)
|
||||
{
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_tinyalsa(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_tinyalsa;
|
||||
ao->flush = flush_tinyalsa;
|
||||
ao->write = write_tinyalsa;
|
||||
ao->get_formats = get_formats_tinyalsa;
|
||||
ao->close = close_tinyalsa;
|
||||
ao->deinit = deinit_tinyalsa;
|
||||
|
||||
/* Allocate memory for data structure */
|
||||
ao->userptr = malloc( sizeof( mpg123_tinyalsa_t ) );
|
||||
if(ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("failed to malloc memory for 'mpg123_tinyalsa_t'");
|
||||
return -1;
|
||||
}
|
||||
memset( ao->userptr, 0, sizeof(mpg123_tinyalsa_t) );
|
||||
|
||||
/* Set card and device */
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
ta->card = 0;
|
||||
ta->device = 0;
|
||||
|
||||
if (ao->device)
|
||||
{
|
||||
char *ptr = ao->device;
|
||||
ta->card = (unsigned int)strtol(ptr, &ptr, 10);
|
||||
if (strlen(ptr) > 0)
|
||||
{
|
||||
ta->device = (unsigned int)strtol(++ptr, &ptr, 10);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get card/device parameters */
|
||||
ta->params = pcm_params_get(ta->card, ta->device, PCM_OUT);
|
||||
if (ta->params == NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error2( "(params) Unable to open card %u PCM device %u.\n"
|
||||
, ta->card, ta->device );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "tinyalsa",
|
||||
/* description */ "Output audio using TINY Advanced Linux Sound Architecture (TINYALSA).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_tinyalsa,
|
||||
};
|
||||
|
||||
305
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/win32.c
vendored
Normal file
305
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/win32.c
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
win32: audio output for Windows 32bit
|
||||
|
||||
copyright ?-2013 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 (as it seems) by Tony Million
|
||||
rewrite of basic functionality for callback-less and properly ringbuffered operation by ravenexp
|
||||
Closing buffer playback fixed by David Wohlferd <limegreensocks (*) yahoo dod com>
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <windows.h>
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
Buffer size and number of buffers in the playback ring
|
||||
NOTE: This particular num/size combination performs best under heavy
|
||||
loads for my system, however this may not be true for any hardware/OS out there.
|
||||
Generally, BUFFER_SIZE < 8k || NUM_BUFFERS > 16 || NUM_BUFFERS < 4 are not recommended.
|
||||
*/
|
||||
#define BUFFER_SIZE 0x10000
|
||||
#define NUM_BUFFERS 8 /* total 512k roughly 2.5 sec of CD quality sound */
|
||||
|
||||
static void wait_for_buffer(WAVEHDR* hdr, HANDLE hEvent);
|
||||
static void drain_win32(out123_handle *ao);
|
||||
|
||||
/* Buffer ring queue state */
|
||||
struct queue_state
|
||||
{
|
||||
WAVEHDR buffer_headers[NUM_BUFFERS];
|
||||
/* The next buffer to be filled and put in playback */
|
||||
int next_buffer;
|
||||
/* Buffer playback completion event */
|
||||
HANDLE play_done_event;
|
||||
HWAVEOUT waveout;
|
||||
};
|
||||
|
||||
static int open_win32(out123_handle *ao)
|
||||
{
|
||||
struct queue_state* state;
|
||||
int i;
|
||||
MMRESULT res;
|
||||
WAVEFORMATEX out_fmt;
|
||||
UINT dev_id;
|
||||
|
||||
if(!ao) return -1;
|
||||
if(ao->rate == -1) return 0;
|
||||
|
||||
/* Allocate queue state struct for this device */
|
||||
state = calloc(1, sizeof(struct queue_state));
|
||||
if(!state) return -1;
|
||||
|
||||
ao->userptr = state;
|
||||
|
||||
state->play_done_event = CreateEvent(0,FALSE,FALSE,0);
|
||||
if(state->play_done_event == INVALID_HANDLE_VALUE) return -1;
|
||||
|
||||
/* FIXME: real device enumeration by capabilities? */
|
||||
dev_id = WAVE_MAPPER; /* probably does the same thing */
|
||||
/* FIXME: support for smth besides MPG123_ENC_SIGNED_16? */
|
||||
out_fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||
out_fmt.wBitsPerSample = 16;
|
||||
out_fmt.nChannels = ao->channels;
|
||||
out_fmt.nSamplesPerSec = ao->rate;
|
||||
out_fmt.nBlockAlign = out_fmt.nChannels*out_fmt.wBitsPerSample/8;
|
||||
out_fmt.nAvgBytesPerSec = out_fmt.nBlockAlign*out_fmt.nSamplesPerSec;
|
||||
out_fmt.cbSize = 0;
|
||||
|
||||
res = waveOutOpen(&state->waveout, dev_id, &out_fmt,
|
||||
(DWORD_PTR)state->play_done_event, 0, CALLBACK_EVENT);
|
||||
|
||||
switch(res)
|
||||
{
|
||||
case MMSYSERR_NOERROR:
|
||||
break;
|
||||
case MMSYSERR_ALLOCATED:
|
||||
ereturn(-1, "Audio output device is already allocated.");
|
||||
case MMSYSERR_NODRIVER:
|
||||
ereturn(-1, "No device driver is present.");
|
||||
case MMSYSERR_NOMEM:
|
||||
ereturn(-1, "Unable to allocate or lock memory.");
|
||||
case WAVERR_BADFORMAT:
|
||||
ereturn(-1, "Unsupported waveform-audio format.");
|
||||
default:
|
||||
ereturn(-1, "Unable to open wave output device.");
|
||||
}
|
||||
|
||||
/* Reset event from the "device open" message */
|
||||
ResetEvent(state->play_done_event);
|
||||
/* Allocate playback buffers */
|
||||
for(i = 0; i < NUM_BUFFERS; i++)
|
||||
if(!(state->buffer_headers[i].lpData = (LPSTR)malloc(BUFFER_SIZE)))
|
||||
{
|
||||
ereturn(-1, "Out of memory for playback buffers.");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Tell waveOutPrepareHeader the maximum value of dwBufferLength
|
||||
we will ever send */
|
||||
state->buffer_headers[i].dwBufferLength = BUFFER_SIZE;
|
||||
state->buffer_headers[i].dwFlags = 0;
|
||||
res = waveOutPrepareHeader(state->waveout, &state->buffer_headers[i], sizeof(WAVEHDR));
|
||||
if(res != MMSYSERR_NOERROR) ereturn(-1, "Can't write to audio output device (prepare).");
|
||||
|
||||
/* set the current size of the buffer to 0 */
|
||||
state->buffer_headers[i].dwBufferLength = 0;
|
||||
|
||||
/* set flags to unprepared - must reset this to WHDR_PREPARED before calling write */
|
||||
state->buffer_headers[i].dwFlags = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wait_for_buffer(WAVEHDR* hdr, HANDLE hEvent)
|
||||
{
|
||||
/* At this point there are several possible states:
|
||||
1) Empty or partial buffer (unqueued) - dwFlags == 0
|
||||
2) Buffer queued or being played - dwFlags == WHDR_PREPARED | WHDR_INQUEUE
|
||||
3) Buffer unqueued and finished being played - dwFlags == WHDR_PREPARED | WHDR_DONE
|
||||
4) Buffer removed from queue, but not yet marked as done - dwFlags == WHDR_PREPARED
|
||||
*/
|
||||
|
||||
/* Check buffer header and wait if it's being played. */
|
||||
if (hdr->dwFlags & WHDR_PREPARED)
|
||||
{
|
||||
while(!(hdr->dwFlags & WHDR_DONE))
|
||||
{
|
||||
/*debug1("waiting for buffer %i...", state->next_buffer);*/
|
||||
/* Waits for *a* buffer to finish. May not be the one we
|
||||
want, so check again */
|
||||
WaitForSingleObject(hEvent, INFINITE);
|
||||
}
|
||||
hdr->dwFlags = 0;
|
||||
hdr->dwBufferLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_formats_win32(out123_handle *ao)
|
||||
{
|
||||
/* FIXME: support for smth besides MPG123_ENC_SIGNED_16? */
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
/* Stores audio data to the fixed size buffers and pushes them into the playback queue.
|
||||
I have one grief with that: The last piece of a track may not reach the output,
|
||||
only full buffers sent... But we don't get smooth audio otherwise. */
|
||||
static int write_win32(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
struct queue_state* state;
|
||||
MMRESULT res;
|
||||
WAVEHDR* hdr;
|
||||
|
||||
int rest_len; /* Input data bytes left for next recursion. */
|
||||
int bufill; /* Bytes we stuff into buffer now. */
|
||||
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
if(!buf || len <= 0) return 0;
|
||||
|
||||
state = (struct queue_state*)ao->userptr;
|
||||
hdr = &state->buffer_headers[state->next_buffer];
|
||||
|
||||
wait_for_buffer(hdr, state->play_done_event);
|
||||
|
||||
/* Now see how much we want to stuff in and then stuff it in. */
|
||||
bufill = BUFFER_SIZE - hdr->dwBufferLength;
|
||||
if(len < bufill) bufill = len;
|
||||
|
||||
rest_len = len - bufill;
|
||||
memcpy(hdr->lpData + hdr->dwBufferLength, buf, bufill);
|
||||
hdr->dwBufferLength += bufill;
|
||||
if(hdr->dwBufferLength == BUFFER_SIZE)
|
||||
{ /* Send the buffer out when it's full. */
|
||||
hdr->dwFlags |= WHDR_PREPARED;
|
||||
|
||||
res = waveOutWrite(state->waveout, hdr, sizeof(WAVEHDR));
|
||||
if(res != MMSYSERR_NOERROR) ereturn(-1, "Can't write to audio output device.");
|
||||
|
||||
/* Cycle to the next buffer in the ring queue */
|
||||
state->next_buffer = (state->next_buffer + 1) % NUM_BUFFERS;
|
||||
}
|
||||
/* I'd like to propagate error codes or something... but there are no catchable surprises left.
|
||||
Anyhow: Here is the recursion that makes ravenexp happy;-) */
|
||||
if(rest_len && write_win32(ao, buf + bufill, rest_len) < 0) /* Write the rest. */
|
||||
return -1;
|
||||
else
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Flush means abort any pending playback */
|
||||
static void flush_win32(out123_handle *ao)
|
||||
{
|
||||
struct queue_state* state;
|
||||
WAVEHDR* hdr;
|
||||
|
||||
if(!ao || !ao->userptr) return;
|
||||
state = (struct queue_state*)ao->userptr;
|
||||
|
||||
/* Cancel any buffers in queue. Ignore errors since we are void and
|
||||
can't return them anyway */
|
||||
waveOutReset(state->waveout);
|
||||
|
||||
/* Discard any partial buffer */
|
||||
hdr = &state->buffer_headers[state->next_buffer];
|
||||
|
||||
/* If WHDR_PREPARED is not set, this is (potentially) a partial buffer */
|
||||
if (!(hdr->dwFlags & WHDR_PREPARED))
|
||||
hdr->dwBufferLength = 0;
|
||||
|
||||
/* Finish processing the buffers */
|
||||
drain_win32(ao);
|
||||
}
|
||||
|
||||
/* output final buffer (if any) */
|
||||
static void write_final_buffer(struct queue_state *state)
|
||||
{
|
||||
WAVEHDR* hdr;
|
||||
hdr = &state->buffer_headers[state->next_buffer];
|
||||
if((!(hdr->dwFlags & WHDR_PREPARED)) && (hdr->dwBufferLength != 0))
|
||||
{
|
||||
hdr->dwFlags |= WHDR_PREPARED;
|
||||
/* ignore any errors */
|
||||
waveOutWrite(state->waveout, hdr, sizeof(WAVEHDR));
|
||||
|
||||
/* Cycle to the next buffer in the ring queue */
|
||||
state->next_buffer = (state->next_buffer + 1) % NUM_BUFFERS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: I tried to fix this stuff without testing.
|
||||
There were some obvious errors in the code.
|
||||
Someone run this on a win32 machine! -- ThOr */
|
||||
static void drain_win32(out123_handle *ao)
|
||||
{
|
||||
int i, z;
|
||||
struct queue_state* state;
|
||||
|
||||
if(!ao || !ao->userptr) return;
|
||||
state = (struct queue_state*)ao->userptr;
|
||||
|
||||
/* output final buffer (if any) */
|
||||
write_final_buffer(state);
|
||||
|
||||
/* I _think_ I understood how this should work. -- ThOr */
|
||||
z = state->next_buffer;
|
||||
for(i = 0; i < NUM_BUFFERS; i++)
|
||||
{
|
||||
wait_for_buffer(&state->buffer_headers[z], state->play_done_event);
|
||||
z = (z + 1) % NUM_BUFFERS;
|
||||
}
|
||||
}
|
||||
|
||||
static int close_win32(out123_handle *ao)
|
||||
{
|
||||
int i;
|
||||
struct queue_state* state;
|
||||
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
state = (struct queue_state*)ao->userptr;
|
||||
|
||||
/* wait for all active buffers to complete */
|
||||
drain_win32(ao);
|
||||
CloseHandle(state->play_done_event);
|
||||
|
||||
for(i = 0; i < NUM_BUFFERS; i++)
|
||||
{
|
||||
state->buffer_headers[i].dwFlags |= WHDR_PREPARED;
|
||||
waveOutUnprepareHeader(state->waveout, &state->buffer_headers[i], sizeof(WAVEHDR));
|
||||
free(state->buffer_headers[i].lpData);
|
||||
}
|
||||
|
||||
waveOutClose(state->waveout);
|
||||
free(ao->userptr);
|
||||
ao->userptr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_win32(out123_handle* ao)
|
||||
{
|
||||
if(!ao) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_win32;
|
||||
ao->flush = flush_win32;
|
||||
ao->write = write_win32;
|
||||
ao->get_formats = get_formats_win32;
|
||||
ao->close = close_win32;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "win32",
|
||||
/* description */ "Audio output for Windows (winmm).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_win32,
|
||||
};
|
||||
497
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/win32_wasapi.c
vendored
Normal file
497
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/win32_wasapi.c
vendored
Normal file
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
win32_wasapi: audio output for Windows wasapi exclusive mode audio
|
||||
|
||||
copyright ?-2013 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
|
||||
|
||||
based on win32.c
|
||||
*/
|
||||
#define _WIN32_WINNT 0x601
|
||||
#define COBJMACROS 1
|
||||
#include "out123_int.h"
|
||||
#include <initguid.h>
|
||||
#include <audioclient.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <avrt.h>
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
/* When compiling C code with MSVC it is only possible to declare, but not
|
||||
define the WASAPI interface GUIDs using MS headers. So we define them
|
||||
ourselves. */
|
||||
|
||||
#ifndef GUID_SECT
|
||||
#define GUID_SECT
|
||||
#endif
|
||||
|
||||
#define __DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
#define __DEFINE_IID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const IID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
#define __DEFINE_CLSID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const CLSID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
#define MPG123_DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
__DEFINE_CLSID(mpg123_CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
#define MPG123_DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
__DEFINE_IID(mpg123_IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
|
||||
// "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"
|
||||
MPG123_DEFINE_IID(IAudioClient, 1cb9ad4c, dbfa, 4c32, b1, 78, c2, f5, 68, a7, 03, b2);
|
||||
// "A95664D2-9614-4F35-A746-DE8DB63617E6"
|
||||
MPG123_DEFINE_IID(IMMDeviceEnumerator, a95664d2, 9614, 4f35, a7, 46, de, 8d, b6, 36, 17, e6);
|
||||
// "BCDE0395-E52F-467C-8E3D-C4579291692E"
|
||||
MPG123_DEFINE_CLSID(IMMDeviceEnumerator, bcde0395, e52f, 467c, 8e, 3d, c4, 57, 92, 91, 69, 2e);
|
||||
// "F294ACFC-3146-4483-A7BF-ADDCA7C260E2"
|
||||
MPG123_DEFINE_IID(IAudioRenderClient, f294acfc, 3146, 4483, a7, bf, ad, dc, a7, c2, 60, e2);
|
||||
#else
|
||||
#define mpg123_IID_IAudioClient IID_IAudioClient
|
||||
#define mpg123_IID_IMMDeviceEnumerator IID_IMMDeviceEnumerator
|
||||
#define mpg123_CLSID_IMMDeviceEnumerator CLSID_MMDeviceEnumerator
|
||||
#define mpg123_IID_IAudioRenderClient IID_IAudioRenderClient
|
||||
#endif
|
||||
|
||||
/* Push mode does not work right yet, noisy audio, probably something to do with timing and buffers */
|
||||
#define WASAPI_EVENT_MODE 1
|
||||
#ifdef WASAPI_EVENT_MODE
|
||||
#define Init_Flag AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
||||
#define MOD_STRING "Experimental Audio output for Windows (wasapi event mode)."
|
||||
#define BUFFER_TIME 20000000.0
|
||||
#else
|
||||
#define Init_Flag 0
|
||||
#define MOD_STRING "Experimental Audio output for Windows (wasapi push mode)."
|
||||
#define BUFFER_TIME 640000000.0
|
||||
#endif
|
||||
|
||||
static int init_win32(out123_handle* ao);
|
||||
static void flush_win32(out123_handle *ao);
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "win32_wasapi",
|
||||
/* description */ MOD_STRING,
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_win32,
|
||||
};
|
||||
|
||||
// REFERENCE_TIME time units per second and per millisecond
|
||||
#define REFTIMES_PER_SEC 10000000
|
||||
#define REFTIMES_PER_MILLISEC 10000
|
||||
|
||||
#define EXIT_ON_ERROR(hres) \
|
||||
if (FAILED(hres)) { goto Exit; }
|
||||
#define SAFE_RELEASE(punk) \
|
||||
if ((punk) != NULL) \
|
||||
{ (punk)->Release(); (punk) = NULL; }
|
||||
|
||||
/* todo: move into handle struct */
|
||||
typedef struct _wasapi_state_struct {
|
||||
IMMDeviceEnumerator *pEnumerator;
|
||||
IMMDevice *pDevice;
|
||||
IAudioClient *pAudioClient;
|
||||
IAudioRenderClient *pRenderClient;
|
||||
BYTE *pData;
|
||||
UINT32 bufferFrameCount;
|
||||
REFERENCE_TIME hnsRequestedDuration;
|
||||
HANDLE hEvent;
|
||||
HANDLE hTask;
|
||||
size_t pData_off;
|
||||
DWORD taskIndex;
|
||||
char is_playing;
|
||||
DWORD framesize;
|
||||
} wasapi_state_struct;
|
||||
|
||||
/* setup endpoints */
|
||||
static int open_win32(out123_handle *ao){
|
||||
HRESULT hr = 0;
|
||||
wasapi_state_struct *state;
|
||||
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || ao->userptr) return -1; /* userptr should really be null */
|
||||
state = calloc(sizeof(*state),1);
|
||||
if(!state) return -1;
|
||||
state->hnsRequestedDuration = REFTIMES_PER_SEC;
|
||||
ao->userptr = (void *)state;
|
||||
|
||||
CoInitialize(NULL);
|
||||
hr = CoCreateInstance(&mpg123_CLSID_IMMDeviceEnumerator,NULL,CLSCTX_ALL, &mpg123_IID_IMMDeviceEnumerator,(void**)&state->pEnumerator);
|
||||
debug("CoCreateInstance");
|
||||
EXIT_ON_ERROR(hr)
|
||||
|
||||
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(state->pEnumerator,eRender, eConsole, &state->pDevice);
|
||||
debug("IMMDeviceEnumerator_GetDefaultAudioEndpoint");
|
||||
EXIT_ON_ERROR(hr)
|
||||
|
||||
hr = IMMDeviceActivator_Activate(state->pDevice,
|
||||
&mpg123_IID_IAudioClient, CLSCTX_ALL,
|
||||
NULL, (void**)&state->pAudioClient);
|
||||
debug("IMMDeviceActivator_Activate");
|
||||
EXIT_ON_ERROR(hr)
|
||||
|
||||
return 0;
|
||||
Exit:
|
||||
debug2("%s failed with %lx", __FUNCTION__, hr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
typedef struct tWAVEFORMATEX {
|
||||
WORD wFormatTag;
|
||||
WORD nChannels;
|
||||
DWORD nSamplesPerSec;
|
||||
DWORD nAvgBytesPerSec;
|
||||
WORD nBlockAlign;
|
||||
WORD wBitsPerSample;
|
||||
WORD cbSize;
|
||||
|
||||
} WAVEFORMATEX;
|
||||
*/
|
||||
|
||||
static int formats_generator(const out123_handle * const ao, const int waveformat, WAVEFORMATEX *const format){
|
||||
DWORD bytes_per_sample = 0;
|
||||
WORD tag = WAVE_FORMAT_PCM;
|
||||
debug1("%s",__FUNCTION__);
|
||||
int ret = waveformat;
|
||||
switch(waveformat){
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
bytes_per_sample = 1;
|
||||
break;
|
||||
case MPG123_ENC_FLOAT_32:
|
||||
tag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
case MPG123_ENC_SIGNED_32:
|
||||
bytes_per_sample = 4;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
bytes_per_sample = 2;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_24:
|
||||
bytes_per_sample = 3;
|
||||
break;
|
||||
default:
|
||||
debug1("uh oh unknown %d",waveformat);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
format->wFormatTag = tag;
|
||||
format->nChannels = ao->channels;
|
||||
format->nSamplesPerSec = ao->rate;
|
||||
format->nAvgBytesPerSec = ao->channels * bytes_per_sample * ao->rate;
|
||||
format->nBlockAlign = ao->channels * bytes_per_sample;
|
||||
format->wBitsPerSample = bytes_per_sample * 8;
|
||||
format->cbSize = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check supported formats */
|
||||
static int get_formats_win32(out123_handle *ao){
|
||||
/* PLEASE check with write_init and write_win32 buffer size calculation in case it is able to support something other than 16bit */
|
||||
HRESULT hr;
|
||||
int ret = 0;
|
||||
debug1("%s",__FUNCTION__);
|
||||
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
debug2("channels %d, rate %ld",ao->channels, ao->rate);
|
||||
|
||||
WAVEFORMATEX wf;
|
||||
|
||||
if(ao->format & MPG123_ENC_SIGNED_8){
|
||||
formats_generator(ao,MPG123_ENC_SIGNED_8,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_SIGNED_8;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_SIGNED_8 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_SIGNED_16){
|
||||
formats_generator(ao,MPG123_ENC_SIGNED_16,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_SIGNED_16;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_SIGNED_16 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_SIGNED_32){
|
||||
formats_generator(ao,MPG123_ENC_SIGNED_32,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_SIGNED_32;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_SIGNED_32 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_FLOAT_32){
|
||||
formats_generator(ao,MPG123_ENC_FLOAT_32,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_FLOAT_32;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_FLOAT_32 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_SIGNED_24){
|
||||
formats_generator(ao,MPG123_ENC_SIGNED_24,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_SIGNED_24;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_SIGNED_24 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
return ret; /* afaik only 16bit 44.1kHz/48kHz has been known to work */
|
||||
}
|
||||
|
||||
/* setup with agreed on format, for now only MPG123_ENC_SIGNED_16 */
|
||||
static int write_init(out123_handle *ao){
|
||||
HRESULT hr;
|
||||
double offset = 0.5;
|
||||
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
|
||||
WAVEFORMATEX s16;
|
||||
formats_generator(ao,ao->format,&s16);
|
||||
state->framesize = s16.nBlockAlign;
|
||||
debug1("block size %ld", state->framesize);
|
||||
/* cargo cult code */
|
||||
hr = IAudioClient_GetDevicePeriod(state->pAudioClient,NULL, &state->hnsRequestedDuration);
|
||||
debug("IAudioClient_GetDevicePeriod OK");
|
||||
reinit:
|
||||
hr = IAudioClient_Initialize(state->pAudioClient,
|
||||
AUDCLNT_SHAREMODE_EXCLUSIVE,
|
||||
Init_Flag,
|
||||
state->hnsRequestedDuration,
|
||||
state->hnsRequestedDuration,
|
||||
&s16,
|
||||
NULL);
|
||||
debug("IAudioClient_Initialize OK");
|
||||
/* something about buffer sizes on Win7, fixme might loop forever */
|
||||
if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED){
|
||||
if (offset > 10.0) goto Exit; /* is 10 enough to break out of the loop?*/
|
||||
debug("AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED");
|
||||
IAudioClient_GetBufferSize(state->pAudioClient,&state->bufferFrameCount);
|
||||
/* double buffered */
|
||||
state->hnsRequestedDuration = (REFERENCE_TIME)((BUFFER_TIME / s16.nSamplesPerSec * state->bufferFrameCount) + offset);
|
||||
offset += 0.5;
|
||||
IAudioClient_Release(state->pAudioClient);
|
||||
state->pAudioClient = NULL;
|
||||
hr = IMMDeviceActivator_Activate(state->pDevice,
|
||||
&mpg123_IID_IAudioClient, CLSCTX_ALL,
|
||||
NULL, (void**)&state->pAudioClient);
|
||||
debug("IMMDeviceActivator_Activate");
|
||||
goto reinit;
|
||||
}
|
||||
EXIT_ON_ERROR(hr)
|
||||
EXIT_ON_ERROR(hr)
|
||||
hr = IAudioClient_GetService(state->pAudioClient,
|
||||
&mpg123_IID_IAudioRenderClient,
|
||||
(void**)&state->pRenderClient);
|
||||
debug("IAudioClient_GetService OK");
|
||||
EXIT_ON_ERROR(hr)
|
||||
#ifdef WASAPI_EVENT_MODE
|
||||
state->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
debug("CreateEvent OK");
|
||||
if(!state->hEvent) goto Exit;
|
||||
hr = IAudioClient_SetEventHandle(state->pAudioClient,state->hEvent);
|
||||
EXIT_ON_ERROR(hr);
|
||||
#endif
|
||||
hr = IAudioClient_GetBufferSize(state->pAudioClient,&state->bufferFrameCount);
|
||||
debug("IAudioClient_GetBufferSize OK");
|
||||
EXIT_ON_ERROR(hr)
|
||||
return 0;
|
||||
Exit:
|
||||
debug2("%s failed with %lx", __FUNCTION__, hr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set play mode if unset, also raise thread priority */
|
||||
static HRESULT play_init(out123_handle *ao){
|
||||
HRESULT hr = S_OK;
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
if(!state->is_playing){
|
||||
debug1("%s",__FUNCTION__);
|
||||
state->hTask = AvSetMmThreadCharacteristicsW(L"Pro Audio", &state->taskIndex);
|
||||
hr = IAudioClient_Start(state->pAudioClient);
|
||||
state->is_playing = 1;
|
||||
debug("IAudioClient_Start");
|
||||
EXIT_ON_ERROR(hr)
|
||||
}
|
||||
return hr;
|
||||
Exit:
|
||||
debug2("%s failed with %lx", __FUNCTION__, hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* copy audio into IAudioRenderClient provided buffer */
|
||||
static int write_win32(out123_handle *ao, unsigned char *buf, int len){
|
||||
HRESULT hr;
|
||||
size_t to_copy = 0;
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
if(!len) return 0;
|
||||
if(!state->pRenderClient) write_init(ao);
|
||||
size_t frames_in = len/state->framesize; /* Frames in buf, is framesize even correct? */
|
||||
debug("mode entered");
|
||||
#ifdef WASAPI_EVENT_MODE
|
||||
/* Event mode WASAPI */
|
||||
DWORD retval = -1;
|
||||
int flag = 0; /* Silence flag */
|
||||
feed_again:
|
||||
if(!state->pData){
|
||||
/* Acquire buffer */
|
||||
hr = IAudioRenderClient_GetBuffer(state->pRenderClient,state->bufferFrameCount, &state->pData);
|
||||
debug("IAudioRenderClient_GetBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
}
|
||||
if(frames_in){ /* Did we get half a frame?? non-zero len smaller than framesize? */
|
||||
/* We must put in exactly the amount of frames specified by IAudioRenderClient_GetBuffer */
|
||||
while(state->pData_off < state->bufferFrameCount){
|
||||
to_copy = state->bufferFrameCount - state->pData_off;
|
||||
debug3("pData_off %I64d, bufferFrameCount %d, to_copy %I64d", state->pData_off, state->bufferFrameCount, to_copy);
|
||||
if(to_copy > frames_in){
|
||||
/* buf can fit in provided buffer space */
|
||||
debug1("all buffers copied, %I64d", frames_in);
|
||||
memcpy(state->pData+state->pData_off*state->framesize,buf,state->framesize*(frames_in));
|
||||
state->pData_off += frames_in;
|
||||
frames_in = 0;
|
||||
break;
|
||||
} else {
|
||||
/* buf too big, needs spliting */
|
||||
debug1("partial buffers %I64d", to_copy);
|
||||
memcpy(state->pData+state->pData_off*state->framesize,buf,state->framesize*(to_copy));
|
||||
state->pData_off += to_copy;
|
||||
buf+=(to_copy*state->framesize);
|
||||
frames_in -= to_copy;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* In case we ever get half a frame, is it possible? */
|
||||
flag = AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
}
|
||||
debug2("Copied %I64d, left %I64d", state->pData_off, frames_in);
|
||||
if(state->pData_off == state->bufferFrameCount) {
|
||||
/* Tell IAudioRenderClient that buffer is filled and released */
|
||||
hr = IAudioRenderClient_ReleaseBuffer(state->pRenderClient,state->pData_off, flag);
|
||||
state->pData_off = 0;
|
||||
state->pData = NULL;
|
||||
debug("IAudioRenderClient_ReleaseBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
if(!state->is_playing){
|
||||
hr = play_init(ao);
|
||||
EXIT_ON_ERROR(hr)
|
||||
}
|
||||
/* wait for next pull event */
|
||||
retval = WaitForSingleObject(state->hEvent, 2000);
|
||||
if (retval != WAIT_OBJECT_0){
|
||||
/* Event handle timed out after a 2-second wait, something went very wrong */
|
||||
IAudioClient_Stop(state->pAudioClient);
|
||||
hr = ERROR_TIMEOUT;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
if(frames_in > 0)
|
||||
goto feed_again;
|
||||
#else /* PUSH mode code */
|
||||
UINT32 numFramesAvailable, numFramesPadding;
|
||||
debug1("block size %ld", state->framesize);
|
||||
feed_again:
|
||||
/* How much buffer do we get to use? */
|
||||
hr = IAudioClient_GetBufferSize(state->pAudioClient,&state->bufferFrameCount);
|
||||
debug("IAudioRenderClient_GetBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
hr = IAudioClient_GetCurrentPadding(state->pAudioClient,&numFramesPadding);
|
||||
debug("IAudioClient_GetCurrentPadding");
|
||||
EXIT_ON_ERROR(hr)
|
||||
/* How much buffer is writable at the moment? */
|
||||
numFramesAvailable = state->bufferFrameCount - numFramesPadding;
|
||||
debug3("numFramesAvailable %d, bufferFrameCount %d, numFramesPadding %d", numFramesAvailable, state->bufferFrameCount, numFramesPadding);
|
||||
if(numFramesAvailable > frames_in){
|
||||
/* can fit all frames now */
|
||||
state->pData_off = 0;
|
||||
to_copy = frames_in;
|
||||
} else {
|
||||
/* copy whatever that fits in the buffer */
|
||||
state->pData_off = frames_in - numFramesAvailable;
|
||||
to_copy = numFramesAvailable;
|
||||
}
|
||||
/* Acquire buffer */
|
||||
hr = IAudioRenderClient_GetBuffer(state->pRenderClient,to_copy,&state->pData);
|
||||
debug("IAudioRenderClient_GetBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
memcpy(state->pData,buf+state->pData_off * state->framesize,to_copy*state->framesize);
|
||||
/* Release buffer */
|
||||
hr = IAudioRenderClient_ReleaseBuffer(state->pRenderClient,to_copy, 0);
|
||||
debug("IAudioRenderClient_ReleaseBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
if(!state->is_playing){
|
||||
hr = play_init(ao);
|
||||
EXIT_ON_ERROR(hr)
|
||||
}
|
||||
frames_in -= to_copy;
|
||||
/* Wait sometime for buffer to empty? */
|
||||
DWORD sleeptime = (DWORD)(state->hnsRequestedDuration/REFTIMES_PER_MILLISEC/ao->rate);
|
||||
debug1("Sleeping %ld msec", sleeptime);
|
||||
Sleep(sleeptime);
|
||||
if (frames_in)
|
||||
goto feed_again;
|
||||
#endif
|
||||
return len;
|
||||
Exit:
|
||||
debug2("%s failed with %lx", __FUNCTION__, hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void flush_win32(out123_handle *ao){
|
||||
/* Wait for the last buffer to play before stopping. */
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || !ao->userptr) return;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
HRESULT hr;
|
||||
if(!state->pAudioClient) return;
|
||||
state->pData = NULL;
|
||||
hr = IAudioClient_Stop(state->pAudioClient);
|
||||
EXIT_ON_ERROR(hr)
|
||||
IAudioClient_Reset(state->pAudioClient);
|
||||
EXIT_ON_ERROR(hr)
|
||||
return;
|
||||
Exit:
|
||||
debug2("%s IAudioClient_Stop with %lx", __FUNCTION__, hr);
|
||||
}
|
||||
|
||||
static int close_win32(out123_handle *ao)
|
||||
{
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
#ifdef WASAPI_EVENT_MODE
|
||||
if(state->pData){
|
||||
/* Play all in buffer before closing */
|
||||
debug("Flushing remaining buffers");
|
||||
IAudioRenderClient_ReleaseBuffer(state->pRenderClient,state->bufferFrameCount, 0);
|
||||
WaitForSingleObject(state->hEvent, 2000);
|
||||
state->pData = NULL;
|
||||
}
|
||||
#endif
|
||||
if(state->pAudioClient) IAudioClient_Stop(state->pAudioClient);
|
||||
if(state->pRenderClient) IAudioRenderClient_Release(state->pRenderClient);
|
||||
if(state->pAudioClient) IAudioClient_Release(state->pAudioClient);
|
||||
if(state->hTask) AvRevertMmThreadCharacteristics(state->hTask);
|
||||
if(state->pEnumerator) IMMDeviceEnumerator_Release(state->pEnumerator);
|
||||
if(state->pDevice) IMMDevice_Release(state->pDevice);
|
||||
CoUninitialize();
|
||||
free(state);
|
||||
ao->userptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_win32(out123_handle* ao){
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_win32;
|
||||
ao->flush = flush_win32;
|
||||
ao->write = write_win32;
|
||||
ao->get_formats = get_formats_win32;
|
||||
ao->close = close_win32;
|
||||
ao->userptr = NULL;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user