From 12fbef0412194772477117caec180482f79e4690 Mon Sep 17 00:00:00 2001 From: Ted Hess Date: Fri, 17 Jul 2015 12:12:18 -0400 Subject: [PATCH] squeezelite: Import new package Signed-off-by: Ted Hess --- sound/squeezelite/Makefile | 146 ++++++++++++++++++ sound/squeezelite/files/squeezelite.conf | 12 ++ sound/squeezelite/files/squeezelite.init | 134 ++++++++++++++++ .../patches/005-respect_LDFLAGS.patch | 56 +++++++ .../patches/010-wait_for_nonzero_mac.patch | 30 ++++ sound/squeezelite/patches/020-no_mpg123.patch | 83 ++++++++++ .../patches/030-fix_musl_compatibilty.patch | 14 ++ .../patches/040-clear_dynlink_errors.patch | 105 +++++++++++++ 8 files changed, 580 insertions(+) create mode 100644 sound/squeezelite/Makefile create mode 100644 sound/squeezelite/files/squeezelite.conf create mode 100644 sound/squeezelite/files/squeezelite.init create mode 100644 sound/squeezelite/patches/005-respect_LDFLAGS.patch create mode 100644 sound/squeezelite/patches/010-wait_for_nonzero_mac.patch create mode 100644 sound/squeezelite/patches/020-no_mpg123.patch create mode 100644 sound/squeezelite/patches/030-fix_musl_compatibilty.patch create mode 100644 sound/squeezelite/patches/040-clear_dynlink_errors.patch diff --git a/sound/squeezelite/Makefile b/sound/squeezelite/Makefile new file mode 100644 index 000000000..8a1274ccf --- /dev/null +++ b/sound/squeezelite/Makefile @@ -0,0 +1,146 @@ +# +# Copyright (C) 2015 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=squeezelite +PKG_VERSION:=1.8 +PKG_RELEASE=1 + +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILES:=LICENSE.txt +PKG_MAINTAINER:= Ted Hess + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://code.google.com/p/squeezelite/ +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=8b8dfe6918ebe45ade5f3d9b68d453d7b8128d99 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_BUILD_DEPENDS:=libflac libvorbis libmad libfaad2 SQUEEZELITE_WMA:libffmpeg-audio-dec + +include $(INCLUDE_DIR)/package.mk + +define Package/squeezelite/default + SECTION:=sound + CATEGORY:=Sound + TITLE:=Headless squeezebox emulator + PROVIDES:=squeezelite + URL:=https://code.google.com/p/squeezelite/ + DEPENDS:= +alsa-lib +SQUEEZELITE_RESAMPLE:libsoxr + MENU:=1 +endef + +define Package/squeezelite-full + $(call Package/squeezelite/default) + TITLE+= (full) + DEPENDS+= +libflac +libvorbis +libmad +libfaad2 \ + +SQUEEZELITE_WMA:libffmpeg-audio-dec + VARIANT:=full +endef + +define Package/squeezelite-mini + $(call Package/squeezelite/default) + TITLE+= (minimal) + VARIANT:=mini +endef + +define Package/squeezelite/config/default + + config SQUEEZELITE_WMA + bool "WMA/ALAC decode support" + help + Include WMA and ALAC decoding using ffmpeg + default n + + config SQUEEZELITE_RESAMPLE + bool "Resample support" + help + Include support for resampling using libsoxr + default n + + config SQUEEZELITE_DSD + bool "DSD playback over PCM (DoP)" + help + Include support for DSD over PCM for compatible DAC" + default n +endef + +define Package/squeezelite-full/config + if PACKAGE_squeezelite-full + $(call Package/squeezelite/config/default) + endif +endef + +define Package/squeezelite-mini/config + if PACKAGE_squeezelite-mini + $(call Package/squeezelite/config/default) + endif +endef + +define Package/squeezelite/description/default + Squeezelite is a small headless squeezebox emulator for linux using alsa audio output + It is aimed at supporting high quality audio at multiple sample rates including + 44.1/48/88.2/96/176.4/192k/352.8/384kHz + Supported codecs: mp3, flac, ogg, aac, (wma and alac via ffmpeg) + Native support for PCM builtin + Optional support of DSD playback via PCM for DoP capable DAC + Optional resampling to match sound device +endef + +define Package/squeezelite/description + $(call Package/squeezelite/description/default) + . + This package has all the audio codecs compiled in. +endef + +define Package/squeezelite-mini/description + $(call Package/squeezelite/description/default) + . + This package will dynamically load installed codecs. +endef + +#ifeq ($(CONFIG_SQUEEZELITE_WMA),y) +# PKG_BUILD_DEPENDS+= libffmpeg-audio-dec +#endif + +TARGET_CFLAGS+= -Wall -fPIC -O2 -DSELFPIPE + +ifeq ($(CONFIG_SQUEEZELITE_WMA),y) + TARGET_CFLAGS+= -DFFMPEG +endif + +ifeq ($(CONFIG_SQUEEZELITE_DSD),y) + TARGET_CFLAGS+= -DDSD +endif + +ifeq ($(CONFIG_SQUEEZELITE_RESAMPLE),y) + TARGET_CFLAGS+= -DRESAMPLE +endif + +TARGET_LDFLAGS+= -lasound -lpthread -lm -lrt + +ifeq ($(BUILD_VARIANT),full) + TARGET_CFLAGS+= -DLINKALL +endif + +define Package/squeezelite/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/squeezelite $(1)/usr/bin + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/squeezelite.init $(1)/etc/init.d/squeezelite + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/squeezelite.conf $(1)/etc/config/squeezelite +endef + +Package/squeezelite-mini/install=$(Package/squeezelite/install) +Package/squeezelite-full/install=$(Package/squeezelite/install) + +$(eval $(call BuildPackage,squeezelite-mini)) +$(eval $(call BuildPackage,squeezelite-full)) diff --git a/sound/squeezelite/files/squeezelite.conf b/sound/squeezelite/files/squeezelite.conf new file mode 100644 index 000000000..57d1b73dd --- /dev/null +++ b/sound/squeezelite/files/squeezelite.conf @@ -0,0 +1,12 @@ + +config options 'options' + option name 'SqueezeWrt' + option model_name 'SqueezeLite' + option close_delay '0' + option priority '0' + option max_sr '0' + option device 'hw:0,0' + option decoder_auto_conf '1' + option dsd_over_pcm '0' + option ircontrol '0' + option enabled '1' diff --git a/sound/squeezelite/files/squeezelite.init b/sound/squeezelite/files/squeezelite.init new file mode 100644 index 000000000..3fa008f63 --- /dev/null +++ b/sound/squeezelite/files/squeezelite.init @@ -0,0 +1,134 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2015 OpenWrt.org + +START=99 +STOP=1 + +USE_PROCD=1 +PROG=/usr/bin/squeezelite + +# +# Auto config checks for existing codec installations if not specified in config +# Explicit disable (override) by setting appropriate "decode_xxx" in config +# +checkcodec() { + config_get_bool auto_conf options "decoder_auto_conf" 1 + config_get_bool codec options "$1" $auto_conf + + if [ $codec -ne 0 ] ; then + if [ $auto_conf -eq 0 ] ; then + #force use requested + echo "$4" + else + if [ -e "/usr/lib/${2}" ] ; then + # Use codec (it exists) + echo "$4" + else + #exclude non-existant + if [ -z "$4" ] ; then + echo "-e $3" + else + echo "$4,$3" + fi + fi + fi + else + # explicitly excluded + if [ -z "$4" ] ; then + echo "-e $3" + else + echo "$4,$3" + fi + fi +} + +make_cmdline() { + cmdline="" + + config_get name options name "SqueezeWrt" + cmdline="$cmdline -n $name" + + config_get model_name options model_name "SqueezeLite" + cmdline="$cmdline -M $model_name" + + config_get device options device "" + [ -n $device ] && cmdline="$cmdline -o $device" + + config_get alsa_buffer options alsa_buffer 200 + [ $alsa_buffer -eq 0 ] && alsa_buffer="200" + + config_get alsa_period options alsa_period 4 + [ $alsa_period -eq 0 ] && alsa_period="4" + + config_get alsa_format options alsa_format 16 + [ $alsa_format = "0" ] && alsa_format="16" + + config_get alsa_mmap options alsa_mmap 0 + cmdline="$cmdline -a $alsa_buffer:$alsa_period:$alsa_format:$alsa_mmap" + + config_get stream_bufsiz options stream_bufsiz 2048 + config_get out_bufsiz options out_bufsiz 3763 + cmdline="$cmdline -b $stream_bufsiz:$out_bufsiz" + + config_get max_sr options max_sr 0 + if [ $max_sr -ne 0 ] ; then + max_sr="-r $max_sr" + + config_get sr_delay options sr_delay 0 + [ $sr_delay -ne 0 ] && max_sr="$max_sr:$sr_delay" + cmdline="$cmdline $max_sr" + fi + + + config_get close_delay options close_delay 0 + [ $close_delay -ne 0 ] && cmdline="$cmdline -C $close_delay" + + config_get server_addr options server_addr "" + if [ -n "$server_addr" ] ; then + config_get server_port options server_port 3483 + cmdline="$cmdline -s $server_addr:$server_port" + fi + + config_get priority options priority 0 + [ $priority -ne 0 ] && cmdline="$cmdline -p $priority" + + # + # ***NOTE: codec lib names are in squeezelite.h (set decode_auto_conf to 0 to ignore) + # + local excl_codecs="" + excl_codecs=`checkcodec decode_flac "libFLAC.so.8" flac "$excl_codecs"` + excl_codecs=`checkcodec decode_mp3 "libmad.so.0" mp3 "$excl_codecs"` + excl_codecs=`checkcodec decode_aac "libfaad.so.2" aac "$excl_codecs"` + excl_codecs=`checkcodec decode_ogg "libvorbisfile.so.3" ogg "$excl_codecs"` + excl_codecs=`checkcodec decode_wma_alac "libavcodec.so.56" wma,alac "$excl_codecs"` + cmdline="$cmdline $excl_codecs" + + config_get dop options dsd_over_pcm 0 + [ $dop -eq 1 ] && cmdline="$cmdline -D" +} + +start_service() { + config_load squeezelite + + config_get_bool enabled options 'enabled' 0 + [ $enabled -eq 0 ] && return + + # Build command params + make_cmdline + + procd_open_instance + logger -t 'squeezelite' "$cmdline" + procd_set_param command "$PROG" $cmdline + procd_close_instance +} + +# Wait for service to exit and release sockets +reload_service() { + stop + sleep 2 + start +} + +restart() { + reload_service +} diff --git a/sound/squeezelite/patches/005-respect_LDFLAGS.patch b/sound/squeezelite/patches/005-respect_LDFLAGS.patch new file mode 100644 index 000000000..d8df7ca23 --- /dev/null +++ b/sound/squeezelite/patches/005-respect_LDFLAGS.patch @@ -0,0 +1,56 @@ +From 1c53ed7db5b49ebf347efe65dbf9b740f9d54557 Mon Sep 17 00:00:00 2001 +From: Carlo Landmeter +Date: Tue, 31 Mar 2015 09:52:53 +0000 +Subject: [PATCH] respect LDFLAGS + +--- + Makefile | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,7 @@ + # Cross compile support - create a Makefile which defines these three variables and then includes this Makefile... +-CFLAGS ?= -Wall -fPIC -O2 $(OPTS) +-LDFLAGS ?= -lasound -lpthread -lm -lrt ++CFLAGS ?= -Wall -O2 ++CFLAGS += -fPIC $(OPTS) ++LIBS ?= -lasound -lpthread -lm -lrt + EXECUTABLE ?= squeezelite + + # passing one or more of these in $(OPTS) enables optional feature inclusion +@@ -52,20 +53,20 @@ endif + + # add optional link options + ifneq (,$(findstring $(OPT_LINKALL), $(CFLAGS))) +- LDFLAGS += $(LINKALL) ++ LIBS += $(LINKALL) + ifneq (,$(findstring $(OPT_FF), $(CFLAGS))) +- LDFLAGS += $(LINKALL_FF) ++ LIBS += $(LINKALL_FF) + endif + ifneq (,$(findstring $(OPT_RESAMPLE), $(CFLAGS))) +- LDFLAGS += $(LINKALL_RESAMPLE) ++ LIBS += $(LINKALL_RESAMPLE) + endif + ifneq (,$(findstring $(OPT_IR), $(CFLAGS))) +- LDFLAGS += $(LINKALL_IR) ++ LIBS += $(LINKALL_IR) + endif + else + # if not LINKALL and linux add LINK_LINUX + ifeq ($(UNAME), Linux) +- LDFLAGS += $(LINK_LINUX) ++ LIBS += $(LINK_LINUX) + endif + endif + +@@ -74,7 +75,7 @@ OBJECTS = $(SOURCES:.c=.o) + all: $(EXECUTABLE) + + $(EXECUTABLE): $(OBJECTS) +- $(CC) $(OBJECTS) $(LDFLAGS) -o $@ ++ $(CC) $(OBJECTS) $(LDFLAGS) $(LIBS) -o $@ + + $(OBJECTS): $(DEPS) + diff --git a/sound/squeezelite/patches/010-wait_for_nonzero_mac.patch b/sound/squeezelite/patches/010-wait_for_nonzero_mac.patch new file mode 100644 index 000000000..69d4f34a8 --- /dev/null +++ b/sound/squeezelite/patches/010-wait_for_nonzero_mac.patch @@ -0,0 +1,30 @@ +--- a/main.c ++++ b/main.c +@@ -187,6 +187,17 @@ static void sighandler(int signum) { + signal(signum, SIG_DFL); + } + ++// Waits for nonzero MAC ++static void get_nonzero_mac(u8_t mac[], u32_t timeout_ms) { ++ u32_t wait_timeout = gettime_ms() + timeout_ms; ++ do{ ++ get_mac(mac); ++ if ((mac[0]+mac[1]+mac[2]+mac[3]+mac[4]+mac[5]) != 0) { ++ break; ++ } ++ }while(wait_timeout > gettime_ms()); ++} ++ + int main(int argc, char **argv) { + char *server = NULL; + char *output_device = "default"; +@@ -240,7 +251,8 @@ int main(int argc, char **argv) { + #define MAXCMDLINE 512 + char cmdline[MAXCMDLINE] = ""; + +- get_mac(mac); ++ // Waits for nonzero MAC ++ get_nonzero_mac(mac,10000); + + for (i = 0; i < argc && (strlen(argv[i]) + strlen(cmdline) + 2 < MAXCMDLINE); i++) { + strcat(cmdline, argv[i]); diff --git a/sound/squeezelite/patches/020-no_mpg123.patch b/sound/squeezelite/patches/020-no_mpg123.patch new file mode 100644 index 000000000..c3eb5d05c --- /dev/null +++ b/sound/squeezelite/patches/020-no_mpg123.patch @@ -0,0 +1,83 @@ +--- a/Makefile ++++ b/Makefile +@@ -15,7 +15,7 @@ OPT_IR = -DIR + SOURCES = \ + main.c slimproto.c buffer.c stream.c utils.c \ + output.c output_alsa.c output_pa.c output_stdout.c output_pack.c decode.c \ +- flac.c pcm.c mad.c vorbis.c faad.c mpg.c ++ flac.c pcm.c mad.c vorbis.c faad.c + + SOURCES_DSD = dsd.c dop.c dsd2pcm/dsd2pcm.c + SOURCES_FF = ffmpeg.c +@@ -25,7 +25,7 @@ SOURCES_IR = ir.c + + LINK_LINUX = -ldl + +-LINKALL = -lFLAC -lmad -lvorbisfile -lfaad -lmpg123 ++LINKALL = -lFLAC -lmad -lvorbisfile -lfaad + LINKALL_FF = -lavcodec -lavformat -lavutil + LINKALL_RESAMPLE = -lsoxr + LINKALL_IR = -llirc_client +--- a/decode.c ++++ b/decode.c +@@ -146,8 +146,8 @@ void decode_init(log_level level, const + // try mad then mpg for mp3 unless command line option passed + if (!(strstr(exclude_codecs, "mp3") || strstr(exclude_codecs, "mad")) && + (!include_codecs || strstr(include_codecs, "mp3") || strstr(include_codecs, "mad"))) codecs[i] = register_mad(); +- if (!(strstr(exclude_codecs, "mp3") || strstr(exclude_codecs, "mpg")) && !codecs[i] && +- (!include_codecs || strstr(include_codecs, "mp3") || strstr(include_codecs, "mpg"))) codecs[i] = register_mpg(); ++// if (!(strstr(exclude_codecs, "mp3") || strstr(exclude_codecs, "mpg")) && !codecs[i] && ++// (!include_codecs || strstr(include_codecs, "mp3") || strstr(include_codecs, "mpg"))) codecs[i] = register_mpg(); + + mutex_create(decode.mutex); + +--- a/main.c ++++ b/main.c +@@ -35,7 +35,8 @@ + #else + #define CODECS_DSD "" + #endif +-#define CODECS_MP3 " (mad,mpg for specific mp3 codec)" ++//#define CODECS_MP3 " (mad,mpg for specific mp3 codec)" ++#define CODECS_MP3 " (mad for specific mp3 codec)" + + #define CODECS CODECS_BASE CODECS_FF CODECS_DSD CODECS_MP3 + +--- a/squeezelite.h ++++ b/squeezelite.h +@@ -140,7 +140,7 @@ + #if LINUX + #define LIBFLAC "libFLAC.so.8" + #define LIBMAD "libmad.so.0" +-#define LIBMPG "libmpg123.so.0" ++//#define LIBMPG "libmpg123.so.0" + #define LIBVORBIS "libvorbisfile.so.3" + #define LIBTREMOR "libvorbisidec.so.1" + #define LIBFAAD "libfaad.so.2" +@@ -154,7 +154,7 @@ + #if OSX + #define LIBFLAC "libFLAC.8.dylib" + #define LIBMAD "libmad.0.dylib" +-#define LIBMPG "libmpg123.0.dylib" ++//#define LIBMPG "libmpg123.0.dylib" + #define LIBVORBIS "libvorbisfile.3.dylib" + #define LIBTREMOR "libvorbisidec.1.dylib" + #define LIBFAAD "libfaad.2.dylib" +@@ -167,7 +167,7 @@ + #if WIN + #define LIBFLAC "libFLAC.dll" + #define LIBMAD "libmad-0.dll" +-#define LIBMPG "libmpg123-0.dll" ++//#define LIBMPG "libmpg123-0.dll" + #define LIBVORBIS "libvorbisfile.dll" + #define LIBTREMOR "libvorbisidec.dll" + #define LIBFAAD "libfaad2.dll" +@@ -180,7 +180,7 @@ + #if FREEBSD + #define LIBFLAC "libFLAC.so.11" + #define LIBMAD "libmad.so.2" +-#define LIBMPG "libmpg123.so.0" ++//#define LIBMPG "libmpg123.so.0" + #define LIBVORBIS "libvorbisfile.so.6" + #define LIBTREMOR "libvorbisidec.so.1" + #define LIBFAAD "libfaad.so.2" diff --git a/sound/squeezelite/patches/030-fix_musl_compatibilty.patch b/sound/squeezelite/patches/030-fix_musl_compatibilty.patch new file mode 100644 index 000000000..86e526015 --- /dev/null +++ b/sound/squeezelite/patches/030-fix_musl_compatibilty.patch @@ -0,0 +1,14 @@ +--- a/output_alsa.c ++++ b/output_alsa.c +@@ -862,8 +862,11 @@ void output_init_alsa(log_level level, c + LOG_INFO("memory locked"); + } + ++#ifdef M_TRIM_THRESHOLD ++ // mallopt is not defined in musl libc + mallopt(M_TRIM_THRESHOLD, -1); + mallopt(M_MMAP_MAX, 0); ++#endif + + touch_memory(silencebuf, MAX_SILENCE_FRAMES * BYTES_PER_FRAME); + touch_memory(outputbuf->buf, outputbuf->size); diff --git a/sound/squeezelite/patches/040-clear_dynlink_errors.patch b/sound/squeezelite/patches/040-clear_dynlink_errors.patch new file mode 100644 index 000000000..157157242 --- /dev/null +++ b/sound/squeezelite/patches/040-clear_dynlink_errors.patch @@ -0,0 +1,105 @@ +--- a/faad.c ++++ b/faad.c +@@ -593,6 +593,8 @@ static bool load_faad() { + return false; + } + ++ err = dlerror(); // Reset previous dynamic linking error string (if there was) ++ + a->NeAACDecGetCurrentConfiguration = dlsym(handle, "NeAACDecGetCurrentConfiguration"); + a->NeAACDecSetConfiguration = dlsym(handle, "NeAACDecSetConfiguration"); + a->NeAACDecOpen = dlsym(handle, "NeAACDecOpen"); +--- a/ffmpeg.c ++++ b/ffmpeg.c +@@ -590,6 +590,8 @@ static bool load_ff() { + return false; + } + ++ err = dlerror(); // Reset previous dynamic linking error string (if there was) ++ + sprintf(name, LIBAVFORMAT, LIBAVFORMAT_VERSION_MAJOR); + handle_format = dlopen(name, RTLD_NOW); + if (!handle_format) { +--- a/flac.c ++++ b/flac.c +@@ -241,6 +241,8 @@ static bool load_flac() { + return false; + } + ++ err = dlerror(); // Reset previous dynamic linking error string (if there was) ++ + f->FLAC__StreamDecoderErrorStatusString = dlsym(handle, "FLAC__StreamDecoderErrorStatusString"); + f->FLAC__StreamDecoderStateString = dlsym(handle, "FLAC__StreamDecoderStateString"); + f->FLAC__stream_decoder_new = dlsym(handle, "FLAC__stream_decoder_new"); +--- a/ir.c ++++ b/ir.c +@@ -167,10 +167,10 @@ static void *ir_thread() { + UNLOCK_I; + wake_controller(); + } +- ++ + free(code); + } +- ++ + return 0; + } + +@@ -184,6 +184,8 @@ static bool load_lirc() { + return false; + } + ++ err = dlerror(); // Reset previous dynamic linking error string (if there was) ++ + i->lirc_init = dlsym(handle, "lirc_init"); + i->lirc_deinit = dlsym(handle, "lirc_deinit"); + i->lirc_readconfig = dlsym(handle, "lirc_readconfig"); +--- a/mad.c ++++ b/mad.c +@@ -364,7 +364,9 @@ static bool load_mad() { + LOG_INFO("dlerror: %s", dlerror()); + return false; + } +- ++ ++ err = dlerror(); // Reset previous dynamic linking error string (if there was) ++ + m->mad_stream_init = dlsym(handle, "mad_stream_init"); + m->mad_frame_init = dlsym(handle, "mad_frame_init"); + m->mad_synth_init = dlsym(handle, "mad_synth_init"); +--- a/mpg.c ++++ b/mpg.c +@@ -221,7 +221,9 @@ static bool load_mpg() { + LOG_INFO("dlerror: %s", dlerror()); + return false; + } +- ++ ++ err = dlerror(); // Reset previous dynamic linking error string (if there was) ++ + m->mpg123_init = dlsym(handle, "mpg123_init"); + m->mpg123_feature = dlsym(handle, "mpg123_feature"); + m->mpg123_rates = dlsym(handle, "mpg123_rates"); +--- a/resample.c ++++ b/resample.c +@@ -250,6 +250,8 @@ static bool load_soxr(void) { + return false; + } + ++ err = dlerror(); // Reset previous dynamic linking error string (if there was) ++ + r->soxr_io_spec = dlsym(handle, "soxr_io_spec"); + r->soxr_quality_spec = dlsym(handle, "soxr_quality_spec"); + r->soxr_create = dlsym(handle, "soxr_create"); +--- a/vorbis.c ++++ b/vorbis.c +@@ -286,6 +286,8 @@ static bool load_vorbis() { + } + } + ++ err = dlerror(); // Reset previous dynamic linking error string (if there was) ++ + v->ov_read = tremor ? NULL : dlsym(handle, "ov_read"); + v->ov_read_tremor = tremor ? dlsym(handle, "ov_read") : NULL; + v->ov_info = dlsym(handle, "ov_info");