Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
975a4ae871 | ||
![]() |
56aaf3c73e | ||
![]() |
12fd1cad0c | ||
![]() |
e573cbf032 | ||
![]() |
dead461542 | ||
![]() |
3d5da1ac73 | ||
![]() |
ec408ca6a6 | ||
![]() |
ea66cdd6a5 | ||
![]() |
f762e8034f | ||
![]() |
bb1e369f30 | ||
![]() |
8376578921 | ||
![]() |
ed2354cd9d | ||
![]() |
386688b87a | ||
![]() |
38d56dddf1 | ||
![]() |
e8975942ec | ||
![]() |
3ca80a7336 | ||
![]() |
d029dae7ad | ||
![]() |
9e058732ee | ||
![]() |
cad5d11261 | ||
![]() |
fcaedec2ab | ||
![]() |
ead9d59e88 | ||
![]() |
34b8a17ccd | ||
![]() |
a53d081c39 | ||
![]() |
823134e4ba | ||
![]() |
272167b4fc | ||
![]() |
92f09bba94 | ||
![]() |
1f50bdb230 | ||
![]() |
2eef4e6716 | ||
![]() |
d989dbfec4 | ||
![]() |
ca9fcec364 | ||
![]() |
354104f9a9 | ||
![]() |
8649ea3d6f | ||
![]() |
752ff12c37 | ||
![]() |
4bb89b1755 | ||
![]() |
0ef553d30e | ||
![]() |
43a62aef07 | ||
![]() |
ed4d0aa909 | ||
![]() |
023ce4e720 | ||
![]() |
368d9359dd | ||
![]() |
d98c19d561 | ||
![]() |
cab77e35e0 | ||
![]() |
e3e90b4b93 | ||
![]() |
f8c69893e1 | ||
![]() |
49678a0893 | ||
![]() |
d667b5b48c | ||
![]() |
9cba55b39c | ||
![]() |
c2cbb7b8ce | ||
![]() |
8217d75ca1 | ||
![]() |
1ca70d9759 | ||
![]() |
4303aaa9b8 | ||
![]() |
7b56bae289 | ||
![]() |
4183416b3e | ||
![]() |
a60dee57ce | ||
![]() |
5724656acb | ||
![]() |
329f9cd9fe | ||
![]() |
fbdb8b406e | ||
![]() |
85d0bbd957 | ||
![]() |
414f00d6ae | ||
![]() |
17b0add058 | ||
![]() |
c68ed40661 | ||
![]() |
ff624075a8 | ||
![]() |
08db28469d | ||
![]() |
a20b326807 | ||
![]() |
4db1b1b250 | ||
![]() |
ff6b263b48 | ||
![]() |
c0bf052fa9 | ||
![]() |
5419cff925 | ||
![]() |
eee10ad2ed | ||
![]() |
98472a8104 | ||
![]() |
d094c168aa | ||
![]() |
4b18460bc6 | ||
![]() |
412c0a965c | ||
![]() |
2becf79223 | ||
![]() |
43ec96d4a0 | ||
![]() |
3d1d779da7 | ||
![]() |
c88056ba83 | ||
![]() |
e769751221 |
Makefile.amNEWS
android
configure.acdoc/include
python/build
src
IOThread.cxxIOThread.hxxMusicPipe.hxxSongFilter.cxxSongFilter.hxx
archive
command
db
decoder
event
filter
input
lib
neighbor
plugins
output
pcm
player
playlist
plugins
queue
storage
thread
util
test
win32
85
Makefile.am
85
Makefile.am
@@ -61,8 +61,8 @@ src_mpd_LDADD = \
|
||||
libnet.a \
|
||||
$(FS_LIBS) \
|
||||
libsystem.a \
|
||||
libutil.a \
|
||||
$(ICU_LDADD) \
|
||||
libutil.a \
|
||||
$(SYSTEMD_DAEMON_LIBS)
|
||||
|
||||
src_mpd_SOURCES = \
|
||||
@@ -285,30 +285,62 @@ libmain_a_CPPFLAGS = $(AM_CPPFLAGS) -Iandroid/build/include
|
||||
|
||||
src_mpd_LDADD += libandroid.a libjava.a
|
||||
|
||||
all-local: android/build/bin/$(APK_NAME)-debug.apk
|
||||
all-local: android/build/$(APK_NAME)-debug.apk
|
||||
clean-local:
|
||||
rm -rf android/build
|
||||
|
||||
libmpd.so: $(filter %.a,$(src_mpd_LDADD)) libmain.a
|
||||
$(AM_V_CXXLD)$(CXXLD) -shared -Wl,--no-undefined,-shared,-Bsymbolic -llog -lz -o $@ $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) src/libmain_a-Main.o $(src_mpd_LDADD) $(LIBS)
|
||||
|
||||
android/build/build.xml: android/AndroidManifest.xml
|
||||
rm -rf android/build
|
||||
mkdir -p android/build/include android/build/res android/build/src/org
|
||||
ln -s $(abs_srcdir)/android/AndroidManifest.xml $(abs_srcdir)/android/custom_rules.xml android/build
|
||||
ln -s $(abs_srcdir)/android/src android/build/src/org/musicpd
|
||||
ln -s $(abs_srcdir)/android/res/values $(abs_srcdir)/android/res/layout android/build/res
|
||||
$(ANDROID_SDK)/tools/android update project --path android/build --target android-17 --name $(APK_NAME)
|
||||
ANDROID_SDK_BUILD_TOOLS_VERSION = 27.0.0
|
||||
ANDROID_SDK_PLATFORM = android-17
|
||||
|
||||
android/build/bin/classes/org/musicpd/Bridge.class: android/src/Bridge.java android/build/build.xml android/build/res/drawable/icon.png
|
||||
cd android/build && ant compile-jni-classes
|
||||
ANDROID_BUILD_TOOLS_DIR = $(ANDROID_SDK)/build-tools/$(ANDROID_SDK_BUILD_TOOLS_VERSION)
|
||||
ANDROID_SDK_PLATFORM_DIR = $(ANDROID_SDK)/platforms/$(ANDROID_SDK_PLATFORM)
|
||||
|
||||
android/build/include/org_musicpd_Bridge.h: android/build/bin/classes/org/musicpd/Bridge.class
|
||||
javah -classpath $(ANDROID_SDK)/platforms/android-17/android.jar:android/build/bin/classes -d $(@D) org.musicpd.Bridge
|
||||
JAVAC = javac
|
||||
AAPT = $(ANDROID_BUILD_TOOLS_DIR)/aapt
|
||||
DX = $(ANDROID_BUILD_TOOLS_DIR)/dx
|
||||
ZIPALIGN = $(ANDROID_BUILD_TOOLS_DIR)/zipalign
|
||||
|
||||
ANDROID_XML_RES := $(wildcard $(srcdir)/android/res/*/*.xml)
|
||||
ANDROID_XML_RES_COPIES := $(patsubst $(srcdir)/android/%,android/build/%,$(ANDROID_XML_RES))
|
||||
|
||||
JAVA_SOURCE_NAMES = Bridge.java Loader.java Main.java
|
||||
JAVA_SOURCE_PATHS = $(addprefix $(srcdir)/android/src/,$(JAVA_SOURCE_NAMES))
|
||||
|
||||
JAVA_CLASSFILES_DIR = android/build/classes
|
||||
|
||||
$(ANDROID_XML_RES_COPIES): $(ANDROID_XML_RES)
|
||||
@$(MKDIR_P) $(dir $@)
|
||||
cp $(patsubst android/build/%,$(srcdir)/android/%,$@) $@
|
||||
|
||||
android/build/resources.apk: $(ANDROID_XML_RES_COPIES) android/build/res/drawable/icon.png
|
||||
@$(MKDIR_P) android/build/gen
|
||||
$(AAPT) package -f -m --auto-add-overlay \
|
||||
--custom-package org.musicpd \
|
||||
-M $(srcdir)/android/AndroidManifest.xml \
|
||||
-S android/build/res \
|
||||
-J android/build/gen \
|
||||
-I $(ANDROID_SDK_PLATFORM_DIR)/android.jar \
|
||||
-F android/build/resources.apk
|
||||
|
||||
# R.java is generated by aapt, when resources.apk is generated
|
||||
android/build/gen/org/musicpd/R.java: android/build/resources.apk
|
||||
|
||||
android/build/classes.dex: $(JAVA_SOURCE_PATHS) android/build/gen/org/musicpd/R.java
|
||||
@$(MKDIR_P) $(JAVA_CLASSFILES_DIR)
|
||||
$(JAVAC) -source 1.5 -target 1.5 -Xlint:-options \
|
||||
-cp $(ANDROID_SDK_PLATFORM_DIR)/android.jar:$(JAVA_CLASSFILES_DIR) \
|
||||
-d $(JAVA_CLASSFILES_DIR) $^
|
||||
$(DX) --dex --output $@ $(JAVA_CLASSFILES_DIR)
|
||||
|
||||
android/build/include/org_musicpd_Bridge.h: android/build/classes.dex
|
||||
javah -classpath $(ANDROID_SDK_PLATFORM_DIR)/android.jar:$(JAVA_CLASSFILES_DIR) -d $(@D) org.musicpd.Bridge
|
||||
|
||||
BUILT_SOURCES = android/build/include/org_musicpd_Bridge.h
|
||||
|
||||
android/build/libs/armeabi-v7a/libmpd.so: libmpd.so android/build/build.xml
|
||||
android/build/lib/armeabi-v7a/libmpd.so: libmpd.so
|
||||
mkdir -p $(@D)
|
||||
rm -f $@
|
||||
$(STRIP) -o $@ $<
|
||||
@@ -317,24 +349,19 @@ android/build/res/drawable/icon.png: mpd.svg
|
||||
mkdir -p $(@D)
|
||||
rsvg-convert --width=48 --height=48 $< -o $@
|
||||
|
||||
APK_DEPS = android/build/res/drawable/icon.png \
|
||||
android/build/libs/armeabi-v7a/libmpd.so \
|
||||
$(wildcard $(srcdir)/android/src/*.java) \
|
||||
android/build/build.xml
|
||||
.DELETE_ON_ERROR: android/build/unsigned.apk
|
||||
android/build/unsigned.apk: android/build/classes.dex android/build/resources.apk android/build/lib/armeabi-v7a/libmpd.so
|
||||
cp android/build/resources.apk $@
|
||||
cd $(dir $@) && zip -q -r $(notdir $@) classes.dex lib
|
||||
|
||||
android/build/bin/$(APK_NAME)-debug.apk: $(APK_DEPS)
|
||||
cd android/build && ant nodeps debug
|
||||
android/build/$(APK_NAME)-debug.apk: android/build/unsigned.apk
|
||||
jarsigner -keystore $(HOME)/.android/debug.keystore -storepass android -signedjar $@ $< androiddebugkey
|
||||
|
||||
android/build/bin/$(APK_NAME)-release-unsigned.apk: $(APK_DEPS)
|
||||
cd android/build && ant nodeps release
|
||||
|
||||
android/build/bin/$(APK_NAME)-release-unaligned.apk: android/build/bin/$(APK_NAME)-release-unsigned.apk
|
||||
android/build/$(APK_NAME)-release-unaligned.apk: android/build/unsigned.apk
|
||||
jarsigner -digestalg SHA1 -sigalg MD5withRSA -storepass:env ANDROID_KEYSTORE_PASS -keystore $(ANDROID_KEYSTORE) -signedjar $@ $< $(ANDROID_KEY_ALIAS)
|
||||
|
||||
ANDROID_SDK_BUILD_TOOLS_VERSION = 20.0.0
|
||||
|
||||
android/build/bin/$(APK_NAME).apk: android/build/bin/$(APK_NAME)-release-unaligned.apk
|
||||
$(ANDROID_SDK)/build-tools/$(ANDROID_SDK_BUILD_TOOLS_VERSION)/zipalign -f 4 $< $@
|
||||
android/build/$(APK_NAME).apk: android/build/$(APK_NAME)-release-unaligned.apk
|
||||
$(ZIPALIGN) -f 4 $< $@
|
||||
|
||||
endif
|
||||
|
||||
@@ -2132,6 +2159,7 @@ test_run_output_LDADD = $(MPD_LIBS) \
|
||||
libutil.a
|
||||
test_run_output_SOURCES = test/run_output.cxx \
|
||||
test/ScopeIOThread.hxx \
|
||||
test/NullMixerListener.hxx \
|
||||
src/Log.cxx src/LogBackend.cxx \
|
||||
src/IOThread.cxx \
|
||||
src/output/Domain.cxx \
|
||||
@@ -2155,6 +2183,7 @@ test_read_mixer_LDADD = \
|
||||
libsystem.a \
|
||||
libutil.a
|
||||
test_read_mixer_SOURCES = test/read_mixer.cxx \
|
||||
test/NullMixerListener.hxx \
|
||||
src/Log.cxx src/LogBackend.cxx \
|
||||
src/mixer/MixerControl.cxx \
|
||||
src/filter/FilterPlugin.cxx \
|
||||
|
29
NEWS
29
NEWS
@@ -1,3 +1,32 @@
|
||||
ver 0.20.16 (2018/02/03)
|
||||
* output
|
||||
- pulse: fix crash during auto-detection
|
||||
* database
|
||||
- simple: fix search within mount points
|
||||
- upnp: enable IPv6
|
||||
* archive
|
||||
- iso9660: libcdio 2.0 compatibility
|
||||
* fix crash in debug build on Haiku and other operating systems
|
||||
|
||||
ver 0.20.15 (2018/01/05)
|
||||
* queue: fix crash after seek failure
|
||||
* resampler
|
||||
- soxr: clear internal state after manual song change
|
||||
* state file
|
||||
- make mount point restore errors non-fatal
|
||||
- fix crash when restoring mounts with incompatible database plugin
|
||||
* Android
|
||||
- build without Ant
|
||||
- fix for SIGSYS crash
|
||||
|
||||
ver 0.20.14 (2018/01/01)
|
||||
* database
|
||||
- simple: fix file corruption in the presence of mount points
|
||||
* archive
|
||||
- bz2: fix deadlock
|
||||
- reduce lock contention, fixing lots of xrun problems
|
||||
* fix Solaris build failure
|
||||
|
||||
ver 0.20.13 (2017/12/18)
|
||||
* output
|
||||
- osx: set up ring buffer to hold at least 100ms
|
||||
|
@@ -2,8 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.musicpd"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="13"
|
||||
android:versionName="0.19.9">
|
||||
android:versionCode="15"
|
||||
android:versionName="0.20.16">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17"/>
|
||||
|
||||
|
@@ -65,7 +65,9 @@ class AndroidNdkToolchain:
|
||||
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
|
||||
llvm_triple = 'armv7-none-linux-androideabi'
|
||||
|
||||
common_flags = '-march=armv7-a -mfloat-abi=softfp'
|
||||
common_flags = '-Os -g'
|
||||
common_flags += ' -fPIC'
|
||||
common_flags += ' -march=armv7-a -mfloat-abi=softfp'
|
||||
|
||||
toolchain_bin = os.path.join(toolchain_path, 'bin')
|
||||
llvm_bin = os.path.join(llvm_path, 'bin')
|
||||
@@ -73,13 +75,15 @@ class AndroidNdkToolchain:
|
||||
self.cxx = os.path.join(llvm_bin, 'clang++')
|
||||
common_flags += ' -target ' + llvm_triple + ' -integrated-as -gcc-toolchain ' + toolchain_path
|
||||
|
||||
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
|
||||
|
||||
self.ar = os.path.join(toolchain_bin, arch + '-ar')
|
||||
self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
|
||||
self.nm = os.path.join(toolchain_bin, arch + '-nm')
|
||||
self.strip = os.path.join(toolchain_bin, arch + '-strip')
|
||||
|
||||
self.cflags = '-Os -g ' + common_flags
|
||||
self.cxxflags = '-Os -g ' + common_flags
|
||||
self.cflags = common_flags
|
||||
self.cxxflags = common_flags
|
||||
self.cppflags = '--sysroot=' + sysroot + \
|
||||
' -isystem ' + os.path.join(install_prefix, 'include') + \
|
||||
' -isystem ' + os.path.join(sysroot, 'usr', 'include', arch) + \
|
||||
@@ -98,15 +102,13 @@ class AndroidNdkToolchain:
|
||||
libcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/llvm-libc++')
|
||||
libcxx_libs_path = os.path.join(libcxx_path, 'libs', android_abi)
|
||||
|
||||
libstdcxx_cppflags = '-nostdinc++ -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
|
||||
libstdcxx_ldadd = os.path.join(libcxx_libs_path, 'libc++_static.a') + ' ' + os.path.join(libcxx_libs_path, 'libc++abi.a')
|
||||
|
||||
if self.is_armv7:
|
||||
libstdcxx_ldadd += ' ' + os.path.join(libcxx_libs_path, 'libunwind.a')
|
||||
libstdcxx_flags = '-stdlib=libc++'
|
||||
libstdcxx_cxxflags = libstdcxx_flags + ' -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
|
||||
libstdcxx_ldflags = libstdcxx_flags + ' -static-libstdc++ -L' + libcxx_libs_path
|
||||
|
||||
if use_cxx:
|
||||
self.libs += ' ' + libstdcxx_ldadd
|
||||
self.cppflags += ' ' + libstdcxx_cppflags
|
||||
self.cxxflags += ' ' + libstdcxx_cxxflags
|
||||
self.ldflags += ' ' + libstdcxx_ldflags
|
||||
|
||||
self.env = dict(os.environ)
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
AC_PREREQ(2.60)
|
||||
|
||||
AC_INIT(mpd, 0.20.13, musicpd-dev-team@lists.sourceforge.net)
|
||||
AC_INIT(mpd, 0.20.16, musicpd-dev-team@lists.sourceforge.net)
|
||||
|
||||
VERSION_MAJOR=0
|
||||
VERSION_MINOR=20
|
||||
VERSION_REVISION=13
|
||||
VERSION_REVISION=16
|
||||
VERSION_EXTRA=0
|
||||
|
||||
AC_CONFIG_SRCDIR([src/Main.cxx])
|
||||
|
@@ -113,7 +113,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_artistid</varname>: the artist id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -122,7 +122,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_albumid</varname>: the album id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -131,7 +131,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_albumartistid</varname>: the album artist
|
||||
id in the <ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -140,7 +140,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_trackid</varname>: the track id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -149,7 +149,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_releasetrackid</varname>: the release track
|
||||
id in the <ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
|
@@ -1,21 +1,30 @@
|
||||
import os.path, subprocess
|
||||
import os.path, subprocess, sys
|
||||
|
||||
from build.project import Project
|
||||
from build.makeproject import MakeProject
|
||||
|
||||
class AutotoolsProject(Project):
|
||||
class AutotoolsProject(MakeProject):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
autogen=False,
|
||||
cppflags='',
|
||||
ldflags='',
|
||||
libs='',
|
||||
subdirs=None,
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
MakeProject.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.autogen = autogen
|
||||
self.cppflags = cppflags
|
||||
self.ldflags = ldflags
|
||||
self.libs = libs
|
||||
self.subdirs = subdirs
|
||||
|
||||
def build(self, toolchain):
|
||||
def configure(self, toolchain):
|
||||
src = self.unpack(toolchain)
|
||||
if self.autogen:
|
||||
subprocess.check_call(['libtoolize', '--force'], cwd=src)
|
||||
if sys.platform == 'darwin':
|
||||
subprocess.check_call(['glibtoolize', '--force'], cwd=src)
|
||||
else:
|
||||
subprocess.check_call(['libtoolize', '--force'], cwd=src)
|
||||
subprocess.check_call(['aclocal'], cwd=src)
|
||||
subprocess.check_call(['automake', '--add-missing', '--force-missing', '--foreign'], cwd=src)
|
||||
subprocess.check_call(['autoconf'], cwd=src)
|
||||
@@ -29,8 +38,8 @@ class AutotoolsProject(Project):
|
||||
'CFLAGS=' + toolchain.cflags,
|
||||
'CXXFLAGS=' + toolchain.cxxflags,
|
||||
'CPPFLAGS=' + toolchain.cppflags + ' ' + self.cppflags,
|
||||
'LDFLAGS=' + toolchain.ldflags,
|
||||
'LIBS=' + toolchain.libs,
|
||||
'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
|
||||
'LIBS=' + toolchain.libs + ' ' + self.libs,
|
||||
'AR=' + toolchain.ar,
|
||||
'RANLIB=' + toolchain.ranlib,
|
||||
'STRIP=' + toolchain.strip,
|
||||
@@ -40,7 +49,12 @@ class AutotoolsProject(Project):
|
||||
] + self.configure_args
|
||||
|
||||
subprocess.check_call(configure, cwd=build, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'],
|
||||
cwd=build, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'],
|
||||
cwd=build, env=toolchain.env)
|
||||
return build
|
||||
|
||||
def build(self, toolchain):
|
||||
build = self.configure(toolchain)
|
||||
if self.subdirs is not None:
|
||||
for subdir in self.subdirs:
|
||||
MakeProject.build(self, toolchain, os.path.join(build, subdir))
|
||||
else:
|
||||
MakeProject.build(self, toolchain, build)
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
from build.project import Project
|
||||
from build.zlib import ZlibProject
|
||||
from build.autotools import AutotoolsProject
|
||||
@@ -5,24 +6,35 @@ from build.ffmpeg import FfmpegProject
|
||||
from build.boost import BoostProject
|
||||
|
||||
libogg = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.xz',
|
||||
'5c3a34309d8b98640827e5d0991a4015',
|
||||
'http://downloads.xiph.org/releases/ogg/libogg-1.3.3.tar.xz',
|
||||
'4f3fc6178a533d392064f14776b23c397ed4b9f48f5de297aba73b643f955c08',
|
||||
'lib/libogg.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
],
|
||||
)
|
||||
|
||||
libvorbis = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz',
|
||||
'28cb28097c07a735d6af56e598e1c90f',
|
||||
'lib/libvorbis.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
],
|
||||
)
|
||||
|
||||
opus = AutotoolsProject(
|
||||
'https://archive.mozilla.org/pub/opus/opus-1.2.1.tar.gz',
|
||||
'cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732',
|
||||
'lib/libopus.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-doc',
|
||||
'--disable-extra-programs',
|
||||
],
|
||||
|
||||
# suppress "visibility default" from opus_defines.h
|
||||
cppflags='-DOPUS_EXPORT=',
|
||||
)
|
||||
|
||||
flac = AutotoolsProject(
|
||||
@@ -32,7 +44,9 @@ flac = AutotoolsProject(
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-xmms-plugin', '--disable-cpplibs',
|
||||
'--disable-doxygen-docs',
|
||||
],
|
||||
subdirs=['include', 'src/libFLAC'],
|
||||
)
|
||||
|
||||
zlib = ZlibProject(
|
||||
@@ -45,21 +59,36 @@ libid3tag = AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libid3tag-0.15.1b.tar.gz',
|
||||
'e5808ad997ba32c498803822078748c3',
|
||||
'lib/libid3tag.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
|
||||
# without this, libid3tag's configure.ac ignores -O* and -f*
|
||||
'--disable-debugging',
|
||||
],
|
||||
autogen=True,
|
||||
|
||||
edits={
|
||||
# fix bug in libid3tag's configure.ac which discards all but the last optimization flag
|
||||
'configure.ac': lambda data: re.sub(r'optimize="\$1"', r'optimize="$optimize $1"', data, count=1),
|
||||
}
|
||||
)
|
||||
|
||||
libmad = AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libmad-0.15.1b.tar.gz',
|
||||
'1be543bc30c56fb6bea1d7bf6a64e66c',
|
||||
'lib/libmad.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
|
||||
# without this, libmad's configure.ac ignores -O* and -f*
|
||||
'--disable-debugging',
|
||||
],
|
||||
autogen=True,
|
||||
)
|
||||
|
||||
liblame = AutotoolsProject(
|
||||
'http://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz',
|
||||
'24346b4158e4af3bd9f2e194bb23eb473c75fb7377011523353196b19b9a23ff',
|
||||
'http://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz',
|
||||
'ddfe36cab873794038ae2c1210557ad34857a4b6bdc515785d1da9e175b1da1e',
|
||||
'lib/libmp3lame.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -89,21 +118,229 @@ ffmpeg = FfmpegProject(
|
||||
'--disable-pixelutils',
|
||||
'--disable-network',
|
||||
'--disable-encoders',
|
||||
'--disable-muxers',
|
||||
'--disable-protocols',
|
||||
'--disable-devices',
|
||||
'--disable-filters',
|
||||
'--disable-filters',
|
||||
'--disable-v4l2_m2m',
|
||||
|
||||
# clang misinterprets the "B0" in hevc_mvs.c as binary
|
||||
# literal, which breaks the build; but we don't need that
|
||||
# video codec anyway
|
||||
'--disable-parser=bmp',
|
||||
'--disable-parser=cavsvideo',
|
||||
'--disable-parser=dvbsub',
|
||||
'--disable-parser=dvdsub',
|
||||
'--disable-parser=dvd_nav',
|
||||
'--disable-parser=flac',
|
||||
'--disable-parser=g729',
|
||||
'--disable-parser=gsm',
|
||||
'--disable-parser=h261',
|
||||
'--disable-parser=h263',
|
||||
'--disable-parser=h264',
|
||||
'--disable-parser=hevc',
|
||||
'--disable-parser=mjpeg',
|
||||
'--disable-parser=mlp',
|
||||
'--disable-parser=mpeg4video',
|
||||
'--disable-parser=mpegaudio',
|
||||
'--disable-parser=mpegvideo',
|
||||
'--disable-parser=opus',
|
||||
'--disable-parser=vc1',
|
||||
'--disable-parser=vp3',
|
||||
'--disable-parser=vp8',
|
||||
'--disable-parser=vp9',
|
||||
'--disable-parser=png',
|
||||
'--disable-parser=pnm',
|
||||
'--disable-parser=xma',
|
||||
|
||||
'--disable-demuxer=aqtitle',
|
||||
'--disable-demuxer=ass',
|
||||
'--disable-demuxer=bethsoftvid',
|
||||
'--disable-demuxer=bink',
|
||||
'--disable-demuxer=cavsvideo',
|
||||
'--disable-demuxer=cdxl',
|
||||
'--disable-demuxer=dvbsub',
|
||||
'--disable-demuxer=dvbtxt',
|
||||
'--disable-demuxer=h261',
|
||||
'--disable-demuxer=h263',
|
||||
'--disable-demuxer=h264',
|
||||
'--disable-demuxer=ico',
|
||||
'--disable-demuxer=image2',
|
||||
'--disable-demuxer=jacosub',
|
||||
'--disable-demuxer=lrc',
|
||||
'--disable-demuxer=microdvd',
|
||||
'--disable-demuxer=mjpeg',
|
||||
'--disable-demuxer=mjpeg_2000',
|
||||
'--disable-demuxer=mpegps',
|
||||
'--disable-demuxer=mpegvideo',
|
||||
'--disable-demuxer=mpl2',
|
||||
'--disable-demuxer=mpsub',
|
||||
'--disable-demuxer=pjs',
|
||||
'--disable-demuxer=rawvideo',
|
||||
'--disable-demuxer=realtext',
|
||||
'--disable-demuxer=sami',
|
||||
'--disable-demuxer=scc',
|
||||
'--disable-demuxer=srt',
|
||||
'--disable-demuxer=stl',
|
||||
'--disable-demuxer=subviewer',
|
||||
'--disable-demuxer=subviewer1',
|
||||
'--disable-demuxer=swf',
|
||||
'--disable-demuxer=tedcaptions',
|
||||
'--disable-demuxer=vobsub',
|
||||
'--disable-demuxer=vplayer',
|
||||
'--disable-demuxer=webvtt',
|
||||
'--disable-demuxer=yuv4mpegpipe',
|
||||
|
||||
# we don't need these decoders, because we have the dedicated
|
||||
# libraries
|
||||
'--disable-decoder=flac',
|
||||
'--disable-decoder=mp1',
|
||||
'--disable-decoder=mp1float',
|
||||
'--disable-decoder=mp2',
|
||||
'--disable-decoder=mp2float',
|
||||
'--disable-decoder=mp3',
|
||||
'--disable-decoder=mp3adu',
|
||||
'--disable-decoder=mp3adufloat',
|
||||
'--disable-decoder=mp3float',
|
||||
'--disable-decoder=mp3on4',
|
||||
'--disable-decoder=mp3on4float',
|
||||
'--disable-decoder=opus',
|
||||
'--disable-decoder=vorbis',
|
||||
|
||||
# audio codecs nobody uses
|
||||
'--disable-decoder=atrac1',
|
||||
'--disable-decoder=atrac3',
|
||||
'--disable-decoder=atrac3al',
|
||||
'--disable-decoder=atrac3p',
|
||||
'--disable-decoder=atrac3pal',
|
||||
'--disable-decoder=binkaudio_dct',
|
||||
'--disable-decoder=binkaudio_rdft',
|
||||
'--disable-decoder=bmv_audio',
|
||||
'--disable-decoder=dsicinaudio',
|
||||
'--disable-decoder=dvaudio',
|
||||
'--disable-decoder=metasound',
|
||||
'--disable-decoder=paf_audio',
|
||||
'--disable-decoder=ra_144',
|
||||
'--disable-decoder=ra_288',
|
||||
'--disable-decoder=ralf',
|
||||
'--disable-decoder=qdm2',
|
||||
'--disable-decoder=qdmc',
|
||||
|
||||
# disable lots of image and video codecs
|
||||
'--disable-decoder=ass',
|
||||
'--disable-decoder=asv1',
|
||||
'--disable-decoder=asv2',
|
||||
'--disable-decoder=apng',
|
||||
'--disable-decoder=avrn',
|
||||
'--disable-decoder=avrp',
|
||||
'--disable-decoder=bethsoftvid',
|
||||
'--disable-decoder=bink',
|
||||
'--disable-decoder=bmp',
|
||||
'--disable-decoder=bmv_video',
|
||||
'--disable-decoder=cavs',
|
||||
'--disable-decoder=ccaption',
|
||||
'--disable-decoder=cdgraphics',
|
||||
'--disable-decoder=clearvideo',
|
||||
'--disable-decoder=dirac',
|
||||
'--disable-decoder=dsicinvideo',
|
||||
'--disable-decoder=dvbsub',
|
||||
'--disable-decoder=dvdsub',
|
||||
'--disable-decoder=dvvideo',
|
||||
'--disable-decoder=exr',
|
||||
'--disable-decoder=ffv1',
|
||||
'--disable-decoder=ffvhuff',
|
||||
'--disable-decoder=ffwavesynth',
|
||||
'--disable-decoder=flic',
|
||||
'--disable-decoder=flv',
|
||||
'--disable-decoder=fraps',
|
||||
'--disable-decoder=gif',
|
||||
'--disable-decoder=h261',
|
||||
'--disable-decoder=h263',
|
||||
'--disable-decoder=h263i',
|
||||
'--disable-decoder=h263p',
|
||||
'--disable-decoder=h264',
|
||||
'--disable-decoder=hevc',
|
||||
'--disable-decoder=hnm4_video',
|
||||
'--disable-decoder=hq_hqa',
|
||||
'--disable-decoder=hqx',
|
||||
'--disable-decoder=idcin',
|
||||
'--disable-decoder=iff_ilbm',
|
||||
'--disable-decoder=indeo2',
|
||||
'--disable-decoder=indeo3',
|
||||
'--disable-decoder=indeo4',
|
||||
'--disable-decoder=indeo5',
|
||||
'--disable-decoder=interplay_video',
|
||||
'--disable-decoder=jacosub',
|
||||
'--disable-decoder=jpeg2000',
|
||||
'--disable-decoder=jpegls',
|
||||
'--disable-decoder=microdvd',
|
||||
'--disable-decoder=mimic',
|
||||
'--disable-decoder=mjpeg',
|
||||
'--disable-decoder=mmvideo',
|
||||
'--disable-decoder=mpl2',
|
||||
'--disable-decoder=motionpixels',
|
||||
'--disable-decoder=mpeg1video',
|
||||
'--disable-decoder=mpeg2video',
|
||||
'--disable-decoder=mpeg4',
|
||||
'--disable-decoder=mpegvideo',
|
||||
'--disable-decoder=mscc',
|
||||
'--disable-decoder=msmpeg4_crystalhd',
|
||||
'--disable-decoder=msmpeg4v1',
|
||||
'--disable-decoder=msmpeg4v2',
|
||||
'--disable-decoder=msmpeg4v3',
|
||||
'--disable-decoder=msvideo1',
|
||||
'--disable-decoder=mszh',
|
||||
'--disable-decoder=mvc1',
|
||||
'--disable-decoder=mvc2',
|
||||
'--disable-decoder=on2avc',
|
||||
'--disable-decoder=paf_video',
|
||||
'--disable-decoder=png',
|
||||
'--disable-decoder=qdraw',
|
||||
'--disable-decoder=qpeg',
|
||||
'--disable-decoder=rawvideo',
|
||||
'--disable-decoder=realtext',
|
||||
'--disable-decoder=roq',
|
||||
'--disable-decoder=roq_dpcm',
|
||||
'--disable-decoder=rscc',
|
||||
'--disable-decoder=rv10',
|
||||
'--disable-decoder=rv20',
|
||||
'--disable-decoder=rv30',
|
||||
'--disable-decoder=rv40',
|
||||
'--disable-decoder=sami',
|
||||
'--disable-decoder=sheervideo',
|
||||
'--disable-decoder=snow',
|
||||
'--disable-decoder=srt',
|
||||
'--disable-decoder=stl',
|
||||
'--disable-decoder=subrip',
|
||||
'--disable-decoder=subviewer',
|
||||
'--disable-decoder=subviewer1',
|
||||
'--disable-decoder=svq1',
|
||||
'--disable-decoder=svq3',
|
||||
'--disable-decoder=tiff',
|
||||
'--disable-decoder=mottiertexseqvideo',
|
||||
'--disable-decoder=truemotion1',
|
||||
'--disable-decoder=truemotion2',
|
||||
'--disable-decoder=truemotion2rt',
|
||||
'--disable-decoder=twinvq',
|
||||
'--disable-decoder=utvideo',
|
||||
'--disable-decoder=vc1',
|
||||
'--disable-decoder=vmdvideo',
|
||||
'--disable-decoder=vp3',
|
||||
'--disable-decoder=vp5',
|
||||
'--disable-decoder=vp6',
|
||||
'--disable-decoder=vp7',
|
||||
'--disable-decoder=vp8',
|
||||
'--disable-decoder=vp9',
|
||||
'--disable-decoder=vqa',
|
||||
'--disable-decoder=webvtt',
|
||||
'--disable-decoder=wmv1',
|
||||
'--disable-decoder=wmv2',
|
||||
'--disable-decoder=wmv3',
|
||||
'--disable-decoder=yuv4',
|
||||
],
|
||||
)
|
||||
|
||||
curl = AutotoolsProject(
|
||||
'http://curl.haxx.se/download/curl-7.57.0.tar.xz',
|
||||
'f5f6fd3c72b7b8389969f4fb671ed8532fa9b5bb7a5cae7ca89bc1cea45c7878',
|
||||
'http://curl.haxx.se/download/curl-7.58.0.tar.xz',
|
||||
'6a813875243609eb75f37fa72044e4ad618b55ec15a4eafdac2df6a7e800e3e3',
|
||||
'lib/libcurl.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -114,6 +351,7 @@ curl = AutotoolsProject(
|
||||
'--disable-ldap', '--disable-ldaps',
|
||||
'--disable-rtsp', '--disable-proxy', '--disable-dict', '--disable-telnet',
|
||||
'--disable-tftp', '--disable-pop3', '--disable-imap', '--disable-smtp',
|
||||
'--disable-smb',
|
||||
'--disable-gopher',
|
||||
'--disable-manual',
|
||||
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
|
||||
@@ -123,7 +361,7 @@ curl = AutotoolsProject(
|
||||
)
|
||||
|
||||
boost = BoostProject(
|
||||
'http://downloads.sourceforge.net/project/boost/boost/1.65.1/boost_1_65_1.tar.bz2',
|
||||
'9807a5d16566c57fd74fb522764e0b134a8bbe6b6e8967b83afefd30dcd3be81',
|
||||
'http://downloads.sourceforge.net/project/boost/boost/1.66.0/boost_1_66_0.tar.bz2',
|
||||
'5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9',
|
||||
'include/boost/version.hpp',
|
||||
)
|
||||
|
28
python/build/makeproject.py
Normal file
28
python/build/makeproject.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import subprocess
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class MakeProject(Project):
|
||||
def __init__(self, url, md5, installed,
|
||||
install_target='install',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.install_target = install_target
|
||||
|
||||
def get_simultaneous_jobs(self):
|
||||
return 12
|
||||
|
||||
def get_make_args(self, toolchain):
|
||||
return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
|
||||
|
||||
def get_make_install_args(self, toolchain):
|
||||
return ['--quiet', self.install_target]
|
||||
|
||||
def make(self, toolchain, wd, args):
|
||||
subprocess.check_call(['/usr/bin/make'] + args,
|
||||
cwd=wd, env=toolchain.env)
|
||||
|
||||
def build(self, toolchain, wd, install=True):
|
||||
self.make(toolchain, wd, self.get_make_args(toolchain))
|
||||
if install:
|
||||
self.make(toolchain, wd, self.get_make_install_args(toolchain))
|
@@ -7,6 +7,7 @@ from build.tar import untar
|
||||
class Project:
|
||||
def __init__(self, url, md5, installed, name=None, version=None,
|
||||
base=None,
|
||||
edits=None,
|
||||
use_cxx=False):
|
||||
if base is None:
|
||||
basename = os.path.basename(url)
|
||||
@@ -28,6 +29,7 @@ class Project:
|
||||
self.md5 = md5
|
||||
self.installed = installed
|
||||
|
||||
self.edits = edits
|
||||
self.use_cxx = use_cxx
|
||||
|
||||
def download(self, toolchain):
|
||||
@@ -47,7 +49,18 @@ class Project:
|
||||
parent_path = toolchain.src_path
|
||||
else:
|
||||
parent_path = toolchain.build_path
|
||||
return untar(self.download(toolchain), parent_path, self.base)
|
||||
path = untar(self.download(toolchain), parent_path, self.base)
|
||||
|
||||
if self.edits is not None:
|
||||
for filename, function in self.edits.items():
|
||||
with open(os.path.join(path, filename), 'r+t') as f:
|
||||
old_data = f.read()
|
||||
new_data = function(old_data)
|
||||
f.seek(0)
|
||||
f.truncate(0)
|
||||
f.write(new_data)
|
||||
|
||||
return path
|
||||
|
||||
def make_build_path(self, toolchain):
|
||||
path = os.path.join(toolchain.build_path, self.base)
|
||||
|
@@ -27,12 +27,17 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static struct {
|
||||
static struct IOThread {
|
||||
Mutex mutex;
|
||||
Cond cond;
|
||||
|
||||
EventLoop *loop;
|
||||
Thread thread;
|
||||
|
||||
IOThread():thread(BIND_THIS_METHOD(Run)) {}
|
||||
|
||||
private:
|
||||
void Run() noexcept;
|
||||
} io;
|
||||
|
||||
void
|
||||
@@ -44,15 +49,15 @@ io_thread_run(void)
|
||||
io.loop->Run();
|
||||
}
|
||||
|
||||
static void
|
||||
io_thread_func(gcc_unused void *arg)
|
||||
inline void
|
||||
IOThread::Run() noexcept
|
||||
{
|
||||
SetThreadName("io");
|
||||
|
||||
/* lock+unlock to synchronize with io_thread_start(), to be
|
||||
sure that io.thread is set */
|
||||
io.mutex.lock();
|
||||
io.mutex.unlock();
|
||||
mutex.lock();
|
||||
mutex.unlock();
|
||||
|
||||
io_thread_run();
|
||||
}
|
||||
@@ -73,7 +78,7 @@ io_thread_start()
|
||||
assert(!io.thread.IsDefined());
|
||||
|
||||
const std::lock_guard<Mutex> protect(io.mutex);
|
||||
io.thread.Start(io_thread_func, nullptr);
|
||||
io.thread.Start();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -103,8 +108,12 @@ io_thread_get() noexcept
|
||||
return *io.loop;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
bool
|
||||
io_thread_inside() noexcept
|
||||
{
|
||||
return io.thread.IsInside();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#ifndef MPD_IO_THREAD_HXX
|
||||
#define MPD_IO_THREAD_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
class EventLoop;
|
||||
@@ -53,6 +54,8 @@ gcc_const
|
||||
EventLoop &
|
||||
io_thread_get() noexcept;
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/**
|
||||
* Is the current thread the I/O thread?
|
||||
*/
|
||||
@@ -61,3 +64,5 @@ bool
|
||||
io_thread_inside() noexcept;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -95,6 +95,7 @@ public:
|
||||
*/
|
||||
gcc_pure
|
||||
const MusicChunk *Peek() const noexcept {
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
return head;
|
||||
}
|
||||
|
||||
@@ -120,6 +121,7 @@ public:
|
||||
*/
|
||||
gcc_pure
|
||||
unsigned GetSize() const noexcept {
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,8 @@
|
||||
#include "tag/Tag.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
#include "util/StringAPI.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/StringView.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/TimeParser.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
@@ -59,7 +61,7 @@ locate_parse_type(const char *str) noexcept
|
||||
|
||||
SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
|
||||
:tag(_tag),
|
||||
value(AllocatedString<>::Duplicate(_value)),
|
||||
value(_value),
|
||||
fold_case(_fold_case ? IcuCompare(value.c_str()) : IcuCompare())
|
||||
{
|
||||
}
|
||||
@@ -274,3 +276,33 @@ SongFilter::GetBase() const noexcept
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SongFilter
|
||||
SongFilter::WithoutBasePrefix(const char *_prefix) const noexcept
|
||||
{
|
||||
const StringView prefix(_prefix);
|
||||
SongFilter result;
|
||||
|
||||
for (const auto &i : items) {
|
||||
if (i.GetTag() == LOCATE_TAG_BASE_TYPE) {
|
||||
const char *s = StringAfterPrefix(i.GetValue(), prefix);
|
||||
if (s != nullptr) {
|
||||
if (*s == 0)
|
||||
continue;
|
||||
|
||||
if (*s == '/') {
|
||||
++s;
|
||||
|
||||
if (*s != 0)
|
||||
result.items.emplace_back(LOCATE_TAG_BASE_TYPE, s);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.items.emplace_back(i);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@@ -21,9 +21,9 @@
|
||||
#define MPD_SONG_FILTER_HXX
|
||||
|
||||
#include "lib/icu/Compare.hxx"
|
||||
#include "util/AllocatedString.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
class Item {
|
||||
uint8_t tag;
|
||||
|
||||
AllocatedString<> value;
|
||||
std::string value;
|
||||
|
||||
/**
|
||||
* This value is only set if case folding is enabled.
|
||||
@@ -66,11 +66,6 @@ public:
|
||||
Item(unsigned tag, const char *value, bool fold_case=false);
|
||||
Item(unsigned tag, time_t time);
|
||||
|
||||
Item(const Item &other) = delete;
|
||||
Item(Item &&) = default;
|
||||
|
||||
Item &operator=(const Item &other) = delete;
|
||||
|
||||
unsigned GetTag() const {
|
||||
return tag;
|
||||
}
|
||||
@@ -157,6 +152,13 @@ public:
|
||||
*/
|
||||
gcc_pure
|
||||
const char *GetBase() const noexcept;
|
||||
|
||||
/**
|
||||
* Create a copy of the filter with the given prefix stripped
|
||||
* from all #LOCATE_TAG_BASE_TYPE items. This is used to
|
||||
* filter songs in mounted databases.
|
||||
*/
|
||||
SongFilter WithoutBasePrefix(const char *prefix) const noexcept;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -162,7 +162,7 @@ Bzip2InputStream::FillBuffer()
|
||||
if (bzstream.avail_in > 0)
|
||||
return true;
|
||||
|
||||
size_t count = archive->istream->Read(buffer, sizeof(buffer));
|
||||
size_t count = archive->istream->LockRead(buffer, sizeof(buffer));
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
@@ -174,6 +174,8 @@ Bzip2InputStream::FillBuffer()
|
||||
size_t
|
||||
Bzip2InputStream::Read(void *ptr, size_t length)
|
||||
{
|
||||
const ScopeUnlock unlock(mutex);
|
||||
|
||||
int bz_result;
|
||||
size_t nbytes = 0;
|
||||
|
||||
@@ -224,4 +226,3 @@ const ArchivePlugin bz2_archive_plugin = {
|
||||
bz2_open,
|
||||
bz2_extensions,
|
||||
};
|
||||
|
||||
|
@@ -115,7 +115,12 @@ Iso9660ArchiveFile::Visit(char *path, size_t length, size_t capacity,
|
||||
visitor.VisitArchiveEntry(path + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#if LIBCDIO_VERSION_NUM >= 20000
|
||||
iso9660_filelist_free(entlist);
|
||||
#else
|
||||
_cdio_list_free (entlist, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
static ArchiveFile *
|
||||
@@ -182,6 +187,8 @@ Iso9660ArchiveFile::OpenStream(const char *pathname,
|
||||
size_t
|
||||
Iso9660InputStream::Read(void *ptr, size_t read_size)
|
||||
{
|
||||
const ScopeUnlock unlock(mutex);
|
||||
|
||||
int readed = 0;
|
||||
int no_blocks, cur_block;
|
||||
size_t left_bytes = statbuf->size - offset;
|
||||
|
@@ -138,6 +138,8 @@ ZzipArchiveFile::OpenStream(const char *pathname,
|
||||
size_t
|
||||
ZzipInputStream::Read(void *ptr, size_t read_size)
|
||||
{
|
||||
const ScopeUnlock unlock(mutex);
|
||||
|
||||
int ret = zzip_file_read(file, ptr, read_size);
|
||||
if (ret < 0)
|
||||
throw std::runtime_error("zzip_file_read() has failed");
|
||||
@@ -155,6 +157,8 @@ ZzipInputStream::IsEOF() noexcept
|
||||
void
|
||||
ZzipInputStream::Seek(offset_type new_offset)
|
||||
{
|
||||
const ScopeUnlock unlock(mutex);
|
||||
|
||||
zzip_off_t ofs = zzip_seek(file, new_offset, SEEK_SET);
|
||||
if (ofs < 0)
|
||||
throw std::runtime_error("zzip_seek() has failed");
|
||||
|
@@ -123,6 +123,10 @@ ToAck(std::exception_ptr ep) noexcept
|
||||
return ACK_ERROR_SYSTEM;
|
||||
} catch (const std::invalid_argument &e) {
|
||||
return ACK_ERROR_ARG;
|
||||
} catch (const std::length_error &e) {
|
||||
return ACK_ERROR_ARG;
|
||||
} catch (const std::out_of_range &e) {
|
||||
return ACK_ERROR_ARG;
|
||||
#ifdef GLIBCXX_49X
|
||||
} catch (const std::exception &e) {
|
||||
#else
|
||||
|
@@ -82,10 +82,11 @@ directory_save(BufferedOutputStream &os, const Directory &directory)
|
||||
}
|
||||
|
||||
for (const auto &child : directory.children) {
|
||||
os.Format(DIRECTORY_DIR "%s\n", child.GetName());
|
||||
if (child.IsMount())
|
||||
continue;
|
||||
|
||||
if (!child.IsMount())
|
||||
directory_save(os, child);
|
||||
os.Format(DIRECTORY_DIR "%s\n", child.GetName());
|
||||
directory_save(os, child);
|
||||
}
|
||||
|
||||
for (const auto &song : directory.songs)
|
||||
|
@@ -20,18 +20,12 @@
|
||||
#include "config.h"
|
||||
#include "Mount.hxx"
|
||||
#include "PrefixedLightSong.hxx"
|
||||
#include "SongFilter.hxx"
|
||||
#include "db/Selection.hxx"
|
||||
#include "db/LightDirectory.hxx"
|
||||
#include "db/Interface.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
|
||||
#ifdef _LIBCPP_VERSION
|
||||
/* workaround for "error: incomplete type 'PlaylistInfo' used in type
|
||||
trait expression" with libc++ version 3900 (from Android NDK
|
||||
r13b) */
|
||||
#include "db/PlaylistInfo.hxx"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
struct PrefixedLightDirectory : LightDirectory {
|
||||
@@ -93,5 +87,16 @@ WalkMount(const char *base, const Database &db,
|
||||
vp = std::bind(PrefixVisitPlaylist,
|
||||
base, std::ref(visit_playlist), _1, _2);
|
||||
|
||||
SongFilter prefix_filter;
|
||||
|
||||
if (base != nullptr && filter != nullptr) {
|
||||
/* if the SongFilter contains a LOCATE_TAG_BASE_TYPE
|
||||
item, copy the SongFilter and drop the mount point
|
||||
from the filter, because the mounted database
|
||||
doesn't know its own location within MPD's VFS */
|
||||
prefix_filter = filter->WithoutBasePrefix(base);
|
||||
filter = &prefix_filter;
|
||||
}
|
||||
|
||||
db.Visit(DatabaseSelection(uri, recursive, filter), vd, vs, vp);
|
||||
}
|
||||
|
@@ -49,6 +49,10 @@ struct UpdateQueueItem {
|
||||
bool IsDefined() const {
|
||||
return id != 0;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
id = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class UpdateQueue {
|
||||
|
@@ -43,6 +43,7 @@ UpdateService::UpdateService(EventLoop &_loop, SimpleDatabase &_db,
|
||||
:DeferredMonitor(_loop),
|
||||
db(_db), storage(_storage),
|
||||
listener(_listener),
|
||||
update_thread(BIND_THIS_METHOD(Task)),
|
||||
update_task_id(0),
|
||||
walk(nullptr)
|
||||
{
|
||||
@@ -140,13 +141,6 @@ UpdateService::Task()
|
||||
DeferredMonitor::Schedule();
|
||||
}
|
||||
|
||||
void
|
||||
UpdateService::Task(void *ctx)
|
||||
{
|
||||
UpdateService &service = *(UpdateService *)ctx;
|
||||
return service.Task();
|
||||
}
|
||||
|
||||
void
|
||||
UpdateService::StartThread(UpdateQueueItem &&i)
|
||||
{
|
||||
@@ -158,7 +152,7 @@ UpdateService::StartThread(UpdateQueueItem &&i)
|
||||
next = std::move(i);
|
||||
walk = new UpdateWalk(GetEventLoop(), listener, *next.storage);
|
||||
|
||||
update_thread.Start(Task, this);
|
||||
update_thread.Start();
|
||||
|
||||
FormatDebug(update_domain,
|
||||
"spawned thread for update job id %i", next.id);
|
||||
@@ -258,7 +252,7 @@ UpdateService::RunDeferred()
|
||||
delete walk;
|
||||
walk = nullptr;
|
||||
|
||||
next = UpdateQueueItem();
|
||||
next.Clear();
|
||||
|
||||
idle_add(IDLE_UPDATE);
|
||||
|
||||
|
@@ -98,7 +98,6 @@ private:
|
||||
|
||||
/* the update thread */
|
||||
void Task();
|
||||
static void Task(void *ctx);
|
||||
|
||||
void StartThread(UpdateQueueItem &&i);
|
||||
|
||||
|
@@ -30,7 +30,8 @@
|
||||
DecoderControl::DecoderControl(Mutex &_mutex, Cond &_client_cond,
|
||||
const AudioFormat _configured_audio_format,
|
||||
const ReplayGainConfig &_replay_gain_config)
|
||||
:mutex(_mutex), client_cond(_client_cond),
|
||||
:thread(BIND_THIS_METHOD(RunThread)),
|
||||
mutex(_mutex), client_cond(_client_cond),
|
||||
configured_audio_format(_configured_audio_format),
|
||||
replay_gain_config(_replay_gain_config) {}
|
||||
|
||||
|
@@ -415,6 +415,9 @@ public:
|
||||
* mixramp_start/mixramp_end.
|
||||
*/
|
||||
void CycleMixRamp();
|
||||
|
||||
private:
|
||||
void RunThread();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -513,30 +513,28 @@ try {
|
||||
dc.client_cond.signal();
|
||||
}
|
||||
|
||||
static void
|
||||
decoder_task(void *arg)
|
||||
void
|
||||
DecoderControl::RunThread()
|
||||
{
|
||||
DecoderControl &dc = *(DecoderControl *)arg;
|
||||
|
||||
SetThreadName("decoder");
|
||||
|
||||
const std::lock_guard<Mutex> protect(dc.mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
do {
|
||||
assert(dc.state == DecoderState::STOP ||
|
||||
dc.state == DecoderState::ERROR);
|
||||
assert(state == DecoderState::STOP ||
|
||||
state == DecoderState::ERROR);
|
||||
|
||||
switch (dc.command) {
|
||||
switch (command) {
|
||||
case DecoderCommand::START:
|
||||
dc.CycleMixRamp();
|
||||
dc.replay_gain_prev_db = dc.replay_gain_db;
|
||||
dc.replay_gain_db = 0;
|
||||
CycleMixRamp();
|
||||
replay_gain_prev_db = replay_gain_db;
|
||||
replay_gain_db = 0;
|
||||
|
||||
decoder_run(dc);
|
||||
decoder_run(*this);
|
||||
|
||||
if (dc.state == DecoderState::ERROR) {
|
||||
if (state == DecoderState::ERROR) {
|
||||
try {
|
||||
std::rethrow_exception(dc.error);
|
||||
std::rethrow_exception(error);
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
} catch (...) {
|
||||
@@ -552,20 +550,20 @@ decoder_task(void *arg)
|
||||
/* we need to clear the pipe here; usually the
|
||||
PlayerThread is responsible, but it is not
|
||||
aware that the decoder has finished */
|
||||
dc.pipe->Clear(*dc.buffer);
|
||||
pipe->Clear(*buffer);
|
||||
|
||||
decoder_run(dc);
|
||||
decoder_run(*this);
|
||||
break;
|
||||
|
||||
case DecoderCommand::STOP:
|
||||
dc.CommandFinishedLocked();
|
||||
CommandFinishedLocked();
|
||||
break;
|
||||
|
||||
case DecoderCommand::NONE:
|
||||
dc.Wait();
|
||||
Wait();
|
||||
break;
|
||||
}
|
||||
} while (dc.command != DecoderCommand::NONE || !dc.quit);
|
||||
} while (command != DecoderCommand::NONE || !quit);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -574,5 +572,5 @@ decoder_thread_start(DecoderControl &dc)
|
||||
assert(!dc.thread.IsDefined());
|
||||
|
||||
dc.quit = false;
|
||||
dc.thread.Start(decoder_task, &dc);
|
||||
dc.thread.Start();
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
EventLoop::EventLoop()
|
||||
:SocketMonitor(*this)
|
||||
:SocketMonitor(*this), quit(false)
|
||||
{
|
||||
SocketMonitor::Open(wake_fd.Get());
|
||||
SocketMonitor::Schedule(SocketMonitor::READ);
|
||||
@@ -46,7 +46,9 @@ EventLoop::~EventLoop()
|
||||
void
|
||||
EventLoop::Break()
|
||||
{
|
||||
quit = true;
|
||||
if (quit.exchange(true))
|
||||
return;
|
||||
|
||||
wake_fd.Write();
|
||||
}
|
||||
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "SocketMonitor.hxx"
|
||||
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
@@ -82,7 +83,7 @@ class EventLoop final : SocketMonitor
|
||||
|
||||
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
|
||||
|
||||
bool quit = false;
|
||||
std::atomic_bool quit;
|
||||
|
||||
/**
|
||||
* True when the object has been modified and another check is
|
||||
|
@@ -73,6 +73,10 @@ public:
|
||||
return filter;
|
||||
}
|
||||
|
||||
void Reset() override {
|
||||
filter->Reset();
|
||||
}
|
||||
|
||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override {
|
||||
return filter->FilterPCM(src);
|
||||
}
|
||||
|
@@ -54,10 +54,10 @@ ThreadInputStream::Start()
|
||||
assert(p != nullptr);
|
||||
|
||||
buffer = new CircularBuffer<uint8_t>((uint8_t *)p, buffer_size);
|
||||
thread.Start(ThreadFunc, this);
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
inline void
|
||||
void
|
||||
ThreadInputStream::ThreadFunc()
|
||||
{
|
||||
FormatThreadName("input:%s", plugin);
|
||||
@@ -107,13 +107,6 @@ ThreadInputStream::ThreadFunc()
|
||||
Close();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadInputStream::ThreadFunc(void *ctx)
|
||||
{
|
||||
ThreadInputStream &tis = *(ThreadInputStream *)ctx;
|
||||
tis.ThreadFunc();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadInputStream::Check()
|
||||
{
|
||||
|
@@ -73,6 +73,7 @@ public:
|
||||
size_t _buffer_size)
|
||||
:InputStream(_uri, _mutex, _cond),
|
||||
plugin(_plugin),
|
||||
thread(BIND_THIS_METHOD(ThreadFunc)),
|
||||
buffer_size(_buffer_size) {}
|
||||
|
||||
virtual ~ThreadInputStream();
|
||||
@@ -138,7 +139,6 @@ protected:
|
||||
|
||||
private:
|
||||
void ThreadFunc();
|
||||
static void ThreadFunc(void *ctx);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -266,6 +266,7 @@ CurlInputStream::OnData(ConstBuffer<void> data)
|
||||
void
|
||||
CurlInputStream::OnEnd()
|
||||
{
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
cond.broadcast();
|
||||
|
||||
AsyncInputStream::SetClosed();
|
||||
@@ -274,6 +275,7 @@ CurlInputStream::OnEnd()
|
||||
void
|
||||
CurlInputStream::OnError(std::exception_ptr e)
|
||||
{
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
postponed_exception = std::move(e);
|
||||
|
||||
if (IsSeekPending())
|
||||
|
@@ -37,6 +37,18 @@ public:
|
||||
|
||||
explicit IcuCompare(const char *needle) noexcept;
|
||||
|
||||
IcuCompare(const IcuCompare &src) noexcept
|
||||
:needle(src
|
||||
? AllocatedString<>::Duplicate(src.needle.c_str())
|
||||
: nullptr) {}
|
||||
|
||||
IcuCompare &operator=(const IcuCompare &src) noexcept {
|
||||
needle = src
|
||||
? AllocatedString<>::Duplicate(src.needle.c_str())
|
||||
: nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IcuCompare(IcuCompare &&) = default;
|
||||
IcuCompare &operator=(IcuCompare &&) = default;
|
||||
|
||||
|
@@ -34,7 +34,11 @@ static unsigned upnp_ref;
|
||||
static void
|
||||
DoInit()
|
||||
{
|
||||
auto code = UpnpInit(0, 0);
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
auto code = UpnpInit2(nullptr, 0);
|
||||
#else
|
||||
auto code = UpnpInit(nullptr, 0);
|
||||
#endif
|
||||
if (code != UPNP_E_SUCCESS)
|
||||
throw FormatRuntimeError("UpnpInit() failed: %s",
|
||||
UpnpGetErrorMessage(code));
|
||||
|
@@ -69,7 +69,8 @@ class SmbclientNeighborExplorer final : public NeighborExplorer {
|
||||
|
||||
public:
|
||||
SmbclientNeighborExplorer(NeighborListener &_listener)
|
||||
:NeighborExplorer(_listener) {}
|
||||
:NeighborExplorer(_listener),
|
||||
thread(BIND_THIS_METHOD(ThreadFunc)) {}
|
||||
|
||||
/* virtual methods from class NeighborExplorer */
|
||||
void Open() override;
|
||||
@@ -79,14 +80,13 @@ public:
|
||||
private:
|
||||
void Run();
|
||||
void ThreadFunc();
|
||||
static void ThreadFunc(void *ctx);
|
||||
};
|
||||
|
||||
void
|
||||
SmbclientNeighborExplorer::Open()
|
||||
{
|
||||
quit = false;
|
||||
thread.Start(ThreadFunc, this);
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -239,6 +239,8 @@ SmbclientNeighborExplorer::Run()
|
||||
inline void
|
||||
SmbclientNeighborExplorer::ThreadFunc()
|
||||
{
|
||||
SetThreadName("smbclient");
|
||||
|
||||
mutex.lock();
|
||||
|
||||
while (!quit) {
|
||||
@@ -257,15 +259,6 @@ SmbclientNeighborExplorer::ThreadFunc()
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void
|
||||
SmbclientNeighborExplorer::ThreadFunc(void *ctx)
|
||||
{
|
||||
SetThreadName("smbclient");
|
||||
|
||||
SmbclientNeighborExplorer &e = *(SmbclientNeighborExplorer *)ctx;
|
||||
e.ThreadFunc();
|
||||
}
|
||||
|
||||
static NeighborExplorer *
|
||||
smbclient_neighbor_create(gcc_unused EventLoop &loop,
|
||||
NeighborListener &listener,
|
||||
|
@@ -51,7 +51,8 @@
|
||||
|
||||
AudioOutput::AudioOutput(const AudioOutputPlugin &_plugin,
|
||||
const ConfigBlock &block)
|
||||
:plugin(_plugin)
|
||||
:plugin(_plugin),
|
||||
thread(BIND_THIS_METHOD(Task))
|
||||
{
|
||||
assert(plugin.finish != nullptr);
|
||||
assert(plugin.open != nullptr);
|
||||
|
@@ -515,7 +515,6 @@ private:
|
||||
* The OutputThread.
|
||||
*/
|
||||
void Task();
|
||||
static void Task(void *arg);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -396,7 +396,7 @@ AudioOutput::Pause()
|
||||
pause = false;
|
||||
}
|
||||
|
||||
inline void
|
||||
void
|
||||
AudioOutput::Task()
|
||||
{
|
||||
FormatThreadName("output:%s", name);
|
||||
@@ -512,17 +512,10 @@ AudioOutput::Task()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioOutput::Task(void *arg)
|
||||
{
|
||||
AudioOutput *ao = (AudioOutput *)arg;
|
||||
ao->Task();
|
||||
}
|
||||
|
||||
void
|
||||
AudioOutput::StartThread()
|
||||
{
|
||||
assert(command == Command::NONE);
|
||||
|
||||
thread.Start(Task, this);
|
||||
thread.Start();
|
||||
}
|
||||
|
@@ -77,7 +77,6 @@ public:
|
||||
void Close();
|
||||
|
||||
size_t Play(const void *chunk, size_t size);
|
||||
void Cancel();
|
||||
|
||||
std::chrono::steady_clock::duration Delay() noexcept;
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "../Wrapper.hxx"
|
||||
#include "mixer/MixerList.hxx"
|
||||
#include "mixer/plugins/PulseMixerPlugin.hxx"
|
||||
#include "util/ScopeExit.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <pulse/thread-mainloop.h>
|
||||
@@ -854,7 +855,10 @@ PulseOutput::TestDefaultDevice()
|
||||
try {
|
||||
const ConfigBlock empty;
|
||||
PulseOutput po(empty);
|
||||
po.Enable();
|
||||
AtScopeExit(&po) { po.Disable(); };
|
||||
po.WaitConnection();
|
||||
|
||||
return true;
|
||||
} catch (const std::runtime_error &e) {
|
||||
return false;
|
||||
|
@@ -122,7 +122,7 @@ sample_format_size(SampleFormat format)
|
||||
* @param format a #SampleFormat enum value
|
||||
* @return the string
|
||||
*/
|
||||
gcc_pure gcc_malloc
|
||||
gcc_pure
|
||||
const char *
|
||||
sample_format_to_string(SampleFormat format) noexcept;
|
||||
|
||||
|
@@ -139,6 +139,14 @@ SoxrPcmResampler::Close()
|
||||
soxr_delete(soxr);
|
||||
}
|
||||
|
||||
void
|
||||
SoxrPcmResampler::Reset()
|
||||
{
|
||||
#if SOXR_THIS_VERSION >= SOXR_VERSION(0,1,2)
|
||||
soxr_clear(soxr);
|
||||
#endif
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
SoxrPcmResampler::Resample(ConstBuffer<void> src)
|
||||
{
|
||||
|
@@ -41,6 +41,7 @@ class SoxrPcmResampler final : public PcmResampler {
|
||||
public:
|
||||
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
||||
void Close() override;
|
||||
void Reset() override;
|
||||
ConstBuffer<void> Resample(ConstBuffer<void> src) override;
|
||||
};
|
||||
|
||||
|
@@ -37,6 +37,7 @@ PlayerControl::PlayerControl(PlayerListener &_listener,
|
||||
buffer_chunks(_buffer_chunks),
|
||||
buffered_before_play(_buffered_before_play),
|
||||
configured_audio_format(_configured_audio_format),
|
||||
thread(BIND_THIS_METHOD(RunThread)),
|
||||
replay_gain_config(_replay_gain_config)
|
||||
{
|
||||
}
|
||||
|
@@ -537,6 +537,9 @@ public:
|
||||
void ApplyEnabled() override {
|
||||
LockUpdateAudio();
|
||||
}
|
||||
|
||||
private:
|
||||
void RunThread();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1147,91 +1147,89 @@ do_play(PlayerControl &pc, DecoderControl &dc,
|
||||
player.Run();
|
||||
}
|
||||
|
||||
static void
|
||||
player_task(void *arg)
|
||||
void
|
||||
PlayerControl::RunThread()
|
||||
{
|
||||
PlayerControl &pc = *(PlayerControl *)arg;
|
||||
|
||||
SetThreadName("player");
|
||||
|
||||
DecoderControl dc(pc.mutex, pc.cond,
|
||||
pc.configured_audio_format,
|
||||
pc.replay_gain_config);
|
||||
DecoderControl dc(mutex, cond,
|
||||
configured_audio_format,
|
||||
replay_gain_config);
|
||||
decoder_thread_start(dc);
|
||||
|
||||
MusicBuffer buffer(pc.buffer_chunks);
|
||||
MusicBuffer buffer(buffer_chunks);
|
||||
|
||||
pc.Lock();
|
||||
Lock();
|
||||
|
||||
while (1) {
|
||||
switch (pc.command) {
|
||||
switch (command) {
|
||||
case PlayerCommand::SEEK:
|
||||
case PlayerCommand::QUEUE:
|
||||
assert(pc.next_song != nullptr);
|
||||
assert(next_song != nullptr);
|
||||
|
||||
pc.Unlock();
|
||||
do_play(pc, dc, buffer);
|
||||
pc.listener.OnPlayerSync();
|
||||
pc.Lock();
|
||||
Unlock();
|
||||
do_play(*this, dc, buffer);
|
||||
listener.OnPlayerSync();
|
||||
Lock();
|
||||
break;
|
||||
|
||||
case PlayerCommand::STOP:
|
||||
pc.Unlock();
|
||||
pc.outputs.Cancel();
|
||||
pc.Lock();
|
||||
Unlock();
|
||||
outputs.Cancel();
|
||||
Lock();
|
||||
|
||||
/* fall through */
|
||||
|
||||
case PlayerCommand::PAUSE:
|
||||
delete pc.next_song;
|
||||
pc.next_song = nullptr;
|
||||
delete next_song;
|
||||
next_song = nullptr;
|
||||
|
||||
pc.CommandFinished();
|
||||
CommandFinished();
|
||||
break;
|
||||
|
||||
case PlayerCommand::CLOSE_AUDIO:
|
||||
pc.Unlock();
|
||||
Unlock();
|
||||
|
||||
pc.outputs.Release();
|
||||
outputs.Release();
|
||||
|
||||
pc.Lock();
|
||||
pc.CommandFinished();
|
||||
Lock();
|
||||
CommandFinished();
|
||||
|
||||
assert(buffer.IsEmptyUnsafe());
|
||||
|
||||
break;
|
||||
|
||||
case PlayerCommand::UPDATE_AUDIO:
|
||||
pc.Unlock();
|
||||
pc.outputs.EnableDisable();
|
||||
pc.Lock();
|
||||
pc.CommandFinished();
|
||||
Unlock();
|
||||
outputs.EnableDisable();
|
||||
Lock();
|
||||
CommandFinished();
|
||||
break;
|
||||
|
||||
case PlayerCommand::EXIT:
|
||||
pc.Unlock();
|
||||
Unlock();
|
||||
|
||||
dc.Quit();
|
||||
|
||||
pc.outputs.Close();
|
||||
outputs.Close();
|
||||
|
||||
pc.LockCommandFinished();
|
||||
LockCommandFinished();
|
||||
return;
|
||||
|
||||
case PlayerCommand::CANCEL:
|
||||
delete pc.next_song;
|
||||
pc.next_song = nullptr;
|
||||
delete next_song;
|
||||
next_song = nullptr;
|
||||
|
||||
pc.CommandFinished();
|
||||
CommandFinished();
|
||||
break;
|
||||
|
||||
case PlayerCommand::REFRESH:
|
||||
/* no-op when not playing */
|
||||
pc.CommandFinished();
|
||||
CommandFinished();
|
||||
break;
|
||||
|
||||
case PlayerCommand::NONE:
|
||||
pc.Wait();
|
||||
Wait();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1242,5 +1240,5 @@ StartPlayerThread(PlayerControl &pc)
|
||||
{
|
||||
assert(!pc.thread.IsDefined());
|
||||
|
||||
pc.thread.Start(player_task, &pc);
|
||||
pc.thread.Start();
|
||||
}
|
||||
|
@@ -313,7 +313,7 @@ soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
|
||||
|
||||
SoundCloudJsonData data;
|
||||
yajl_handle hand = yajl_alloc(&parse_callbacks, nullptr, &data);
|
||||
AtScopeExit(hand, &data) { yajl_free(hand); };
|
||||
AtScopeExit(hand) { yajl_free(hand); };
|
||||
|
||||
int ret = soundcloud_parse_json(u, hand, mutex, cond);
|
||||
|
||||
|
@@ -212,8 +212,6 @@ playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time)
|
||||
{
|
||||
assert(queue.IsValidOrder(i));
|
||||
|
||||
const DetachedSong *queued_song = GetQueuedSong();
|
||||
|
||||
pc.LockClearError();
|
||||
stop_on_error = true;
|
||||
error_count = 0;
|
||||
@@ -226,8 +224,6 @@ playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time)
|
||||
|
||||
playing = true;
|
||||
current = i;
|
||||
|
||||
queued_song = nullptr;
|
||||
}
|
||||
|
||||
queued = -1;
|
||||
@@ -235,7 +231,7 @@ playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time)
|
||||
try {
|
||||
pc.LockSeek(new DetachedSong(queue.GetOrder(i)), seek_time);
|
||||
} catch (...) {
|
||||
UpdateQueuedSong(pc, queued_song);
|
||||
UpdateQueuedSong(pc, nullptr);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,7 @@
|
||||
#include "IOThread.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <boost/crc.hpp>
|
||||
|
||||
#define MOUNT_STATE_BEGIN "mount_begin"
|
||||
@@ -48,6 +48,9 @@ static constexpr Domain storage_domain("storage");
|
||||
void
|
||||
storage_state_save(BufferedOutputStream &os, const Instance &instance)
|
||||
{
|
||||
if (instance.storage == nullptr)
|
||||
return;
|
||||
|
||||
const auto visitor = [&os](const char *mount_uri, const Storage &storage) {
|
||||
std::string uri = storage.MapUTF8("");
|
||||
if (uri.empty() || StringIsEmpty(mount_uri))
|
||||
@@ -85,6 +88,12 @@ storage_state_restore(const char *line, TextFile &file, Instance &instance)
|
||||
FormatError(storage_domain, "Unrecognized line in mountpoint state: %s", line);
|
||||
}
|
||||
|
||||
if (instance.storage == nullptr)
|
||||
/* without storage (a CompositeStorage instance), we
|
||||
cannot mount, and therefore we silently ignore the
|
||||
state file */
|
||||
return true;
|
||||
|
||||
if (url.empty() || uri.empty()) {
|
||||
LogError(storage_domain, "Missing value in mountpoint state.");
|
||||
return true;
|
||||
@@ -99,16 +108,18 @@ storage_state_restore(const char *line, TextFile &file, Instance &instance)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
Database *db = instance.database;
|
||||
if (db != nullptr && db->IsPlugin(simple_db_plugin)) {
|
||||
try {
|
||||
((SimpleDatabase *)db)->Mount(uri.c_str(), url.c_str());
|
||||
} catch (...) {
|
||||
throw;
|
||||
delete storage;
|
||||
FormatError(std::current_exception(),
|
||||
"Failed to restore mount to %s",
|
||||
url.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
((CompositeStorage*)instance.storage)->Mount(uri.c_str(), storage);
|
||||
|
||||
@@ -118,16 +129,17 @@ storage_state_restore(const char *line, TextFile &file, Instance &instance)
|
||||
unsigned
|
||||
storage_state_get_hash(const Instance &instance)
|
||||
{
|
||||
std::list<std::string> mounts;
|
||||
if (instance.storage == nullptr)
|
||||
return 0;
|
||||
|
||||
std::set<std::string> mounts;
|
||||
|
||||
const auto visitor = [&mounts](const char *mount_uri, const Storage &storage) {
|
||||
mounts.push_back(std::string(mount_uri) + ":" + storage.MapUTF8(""));
|
||||
mounts.emplace(std::string(mount_uri) + ":" + storage.MapUTF8(""));
|
||||
};
|
||||
|
||||
((CompositeStorage*)instance.storage)->VisitMounts(visitor);
|
||||
|
||||
mounts.sort();
|
||||
|
||||
boost::crc_32_type result;
|
||||
|
||||
for (auto mount: mounts) {
|
||||
|
@@ -52,13 +52,11 @@ public:
|
||||
constexpr ThreadId(pthread_t _id):id(_id) {}
|
||||
#endif
|
||||
|
||||
gcc_const
|
||||
static ThreadId Null() noexcept {
|
||||
static constexpr ThreadId Null() noexcept {
|
||||
#ifdef _WIN32
|
||||
return 0;
|
||||
#else
|
||||
static ThreadId null;
|
||||
return null;
|
||||
return pthread_t();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -81,11 +79,13 @@ public:
|
||||
|
||||
gcc_pure
|
||||
bool operator==(const ThreadId &other) const noexcept {
|
||||
#ifdef _WIN32
|
||||
/* note: not using pthread_equal() because that
|
||||
function "is undefined if either thread ID is not
|
||||
valid so we can't safely use it on
|
||||
default-constructed values" (comment from
|
||||
libstdc++) - and if both libstdc++ and libc++ get
|
||||
away with this, we can do it as well */
|
||||
return id == other.id;
|
||||
#else
|
||||
return pthread_equal(id, other.id);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -25,39 +25,21 @@
|
||||
#include "java/Global.hxx"
|
||||
#endif
|
||||
|
||||
bool
|
||||
Thread::Start(void (*_f)(void *ctx), void *_ctx)
|
||||
void
|
||||
Thread::Start()
|
||||
{
|
||||
assert(!IsDefined());
|
||||
|
||||
f = _f;
|
||||
ctx = _ctx;
|
||||
|
||||
#ifdef _WIN32
|
||||
handle = ::CreateThread(nullptr, 0, ThreadProc, this, 0, &id);
|
||||
if (handle == nullptr)
|
||||
throw MakeLastError("Failed to create thread");
|
||||
#else
|
||||
#ifndef NDEBUG
|
||||
creating = true;
|
||||
#endif
|
||||
|
||||
int e = pthread_create(&handle, nullptr, ThreadProc, this);
|
||||
|
||||
if (e != 0) {
|
||||
#ifndef NDEBUG
|
||||
creating = false;
|
||||
#endif
|
||||
if (e != 0)
|
||||
throw MakeErrno(e, "Failed to create thread");
|
||||
}
|
||||
|
||||
defined = true;
|
||||
#ifndef NDEBUG
|
||||
creating = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -72,7 +54,17 @@ Thread::Join()
|
||||
handle = nullptr;
|
||||
#else
|
||||
pthread_join(handle, nullptr);
|
||||
defined = false;
|
||||
handle = pthread_t();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void
|
||||
Thread::Run()
|
||||
{
|
||||
f();
|
||||
|
||||
#ifdef ANDROID
|
||||
Java::DetachCurrentThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -83,7 +75,7 @@ Thread::ThreadProc(LPVOID ctx)
|
||||
{
|
||||
Thread &thread = *(Thread *)ctx;
|
||||
|
||||
thread.f(thread.ctx);
|
||||
thread.Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -95,18 +87,10 @@ Thread::ThreadProc(void *ctx)
|
||||
Thread &thread = *(Thread *)ctx;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* this works around a race condition that causes an assertion
|
||||
failure due to IsInside() spuriously returning false right
|
||||
after the thread has been created, and the calling thread
|
||||
hasn't initialised "defined" yet */
|
||||
thread.defined = true;
|
||||
thread.inside_handle = pthread_self();
|
||||
#endif
|
||||
|
||||
thread.f(thread.ctx);
|
||||
|
||||
#ifdef ANDROID
|
||||
Java::DetachCurrentThread();
|
||||
#endif
|
||||
thread.Run();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#define MPD_THREAD_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "util/BindMethod.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -32,28 +33,28 @@
|
||||
#include <assert.h>
|
||||
|
||||
class Thread {
|
||||
typedef BoundMethod<void()> Function;
|
||||
const Function f;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE handle = nullptr;
|
||||
DWORD id;
|
||||
#else
|
||||
pthread_t handle;
|
||||
bool defined = false;
|
||||
pthread_t handle = pthread_t();
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
* The thread is currently being created. This is a workaround for
|
||||
* IsInside(), which may return false until pthread_create() has
|
||||
* initialised the #handle.
|
||||
* This handle is only used by IsInside(), and is set by the
|
||||
* thread function. Since #handle is set by pthread_create()
|
||||
* which is racy, we need this attribute for early checks
|
||||
* inside the thread function.
|
||||
*/
|
||||
bool creating = false;
|
||||
pthread_t inside_handle = pthread_t();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void (*f)(void *ctx);
|
||||
void *ctx;
|
||||
|
||||
public:
|
||||
Thread() = default;
|
||||
explicit Thread(Function _f):f(_f) {}
|
||||
|
||||
Thread(const Thread &) = delete;
|
||||
|
||||
@@ -69,10 +70,11 @@ public:
|
||||
#ifdef _WIN32
|
||||
return handle != nullptr;
|
||||
#else
|
||||
return defined;
|
||||
return handle != pthread_t();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
* Check if this thread is the current thread.
|
||||
*/
|
||||
@@ -81,18 +83,23 @@ public:
|
||||
#ifdef _WIN32
|
||||
return GetCurrentThreadId() == id;
|
||||
#else
|
||||
#ifdef NDEBUG
|
||||
constexpr bool creating = false;
|
||||
#endif
|
||||
return IsDefined() && (creating ||
|
||||
pthread_equal(pthread_self(), handle));
|
||||
/* note: not using pthread_equal() because that
|
||||
function "is undefined if either thread ID is not
|
||||
valid so we can't safely use it on
|
||||
default-constructed values" (comment from
|
||||
libstdc++) - and if both libstdc++ and libc++ get
|
||||
away with this, we can do it as well */
|
||||
return pthread_self() == inside_handle;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Start(void (*f)(void *ctx), void *ctx);
|
||||
void Start();
|
||||
void Join();
|
||||
|
||||
private:
|
||||
void Run();
|
||||
|
||||
#ifdef _WIN32
|
||||
static DWORD WINAPI ThreadProc(LPVOID ctx);
|
||||
#else
|
||||
|
@@ -38,7 +38,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) && !defined(ANDROID)
|
||||
|
||||
static int
|
||||
ioprio_set(int which, int who, int ioprio)
|
||||
@@ -69,7 +69,11 @@ SetThreadIdlePriority()
|
||||
sched_setscheduler(0, SCHED_IDLE, &sched_param);
|
||||
#endif
|
||||
|
||||
#ifndef ANDROID
|
||||
/* this system call is forbidden via seccomp on Android 8 and
|
||||
leads to crash (SIGSYS) */
|
||||
ioprio_set_idle();
|
||||
#endif
|
||||
|
||||
#elif defined(_WIN32)
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
|
||||
|
@@ -42,11 +42,6 @@ class RefCount {
|
||||
std::atomic_uint n;
|
||||
|
||||
public:
|
||||
#ifndef _LIBCPP_VERSION
|
||||
/* the "constexpr" is missing in libc++'s "atomic"
|
||||
implementation */
|
||||
constexpr
|
||||
#endif
|
||||
RefCount():n(1) {}
|
||||
|
||||
void Increment() {
|
||||
|
@@ -103,11 +103,13 @@ UnsafeCopyStringP(wchar_t *dest, const wchar_t *src) noexcept
|
||||
{
|
||||
#if defined(_WIN32) || defined(__BIONIC__) || defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
/* emulate wcpcpy() */
|
||||
UnsafeCopyString(dest, src);
|
||||
return dest + StringLength(dest);
|
||||
/* emulate wcpcpy() */
|
||||
UnsafeCopyString(dest, src);
|
||||
return dest + StringLength(dest);
|
||||
#elif defined(__sun) && defined (__SVR4)
|
||||
return std::wcpcpy(dest, src);
|
||||
#else
|
||||
return wcpcpy(dest, src);
|
||||
return wcpcpy(dest, src);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -140,7 +142,11 @@ gcc_malloc gcc_nonnull_all
|
||||
static inline wchar_t *
|
||||
DuplicateString(const wchar_t *p)
|
||||
{
|
||||
#if defined(__sun) && defined (__SVR4)
|
||||
return std::wcsdup(p);
|
||||
#else
|
||||
return wcsdup(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
30
test/NullMixerListener.hxx
Normal file
30
test/NullMixerListener.hxx
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef NULL_MIXER_LISTENER_HXX
|
||||
#define NULL_MIXER_LISTENER_HXX
|
||||
|
||||
#include "mixer/Listener.hxx"
|
||||
|
||||
class NullMixerListener : public MixerListener {
|
||||
public:
|
||||
void OnMixerVolumeChanged(Mixer &, int) override {}
|
||||
};
|
||||
|
||||
#endif
|
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "NullMixerListener.hxx"
|
||||
#include "mixer/MixerControl.hxx"
|
||||
#include "mixer/MixerList.hxx"
|
||||
#include "filter/FilterRegistry.hxx"
|
||||
@@ -50,9 +51,14 @@ try {
|
||||
|
||||
EventLoop event_loop;
|
||||
|
||||
NullMixerListener mixer_listener;
|
||||
Mixer *mixer = mixer_new(event_loop, alsa_mixer_plugin,
|
||||
*(AudioOutput *)nullptr,
|
||||
*(MixerListener *)nullptr,
|
||||
/* ugly dangerous dummy pointer to
|
||||
make the compiler happy; this
|
||||
works with most mixers, because
|
||||
they don't need the AudioOutput */
|
||||
*(AudioOutput *)0x1,
|
||||
mixer_listener,
|
||||
ConfigBlock());
|
||||
|
||||
mixer_open(mixer);
|
||||
|
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "NullMixerListener.hxx"
|
||||
#include "output/Internal.hxx"
|
||||
#include "output/OutputPlugin.hxx"
|
||||
#include "output/Client.hxx"
|
||||
@@ -44,6 +45,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void AudioOutput::Task() {}
|
||||
|
||||
class DummyAudioOutputClient final : public AudioOutputClient {
|
||||
public:
|
||||
/* virtual methods from AudioOutputClient */
|
||||
@@ -62,7 +65,9 @@ filter_plugin_by_name(gcc_unused const char *name) noexcept
|
||||
}
|
||||
|
||||
static AudioOutput *
|
||||
load_audio_output(EventLoop &event_loop, AudioOutputClient &client,
|
||||
load_audio_output(EventLoop &event_loop,
|
||||
NullMixerListener &mixer_listener,
|
||||
AudioOutputClient &client,
|
||||
const char *name)
|
||||
{
|
||||
const auto *param = config_find_block(ConfigBlockOption::AUDIO_OUTPUT,
|
||||
@@ -72,7 +77,7 @@ load_audio_output(EventLoop &event_loop, AudioOutputClient &client,
|
||||
name);
|
||||
|
||||
return audio_output_new(event_loop, ReplayGainConfig(), *param,
|
||||
*(MixerListener *)nullptr,
|
||||
mixer_listener,
|
||||
client);
|
||||
}
|
||||
|
||||
@@ -142,8 +147,10 @@ try {
|
||||
|
||||
/* initialize the audio output */
|
||||
|
||||
NullMixerListener mixer_listener;
|
||||
DummyAudioOutputClient client;
|
||||
AudioOutput *ao = load_audio_output(event_loop, client, argv[2]);
|
||||
AudioOutput *ao = load_audio_output(event_loop, mixer_listener,
|
||||
client, argv[2]);
|
||||
|
||||
/* parse the audio format */
|
||||
|
||||
|
@@ -50,14 +50,14 @@ class CrossGccToolchain:
|
||||
self.nm = os.path.join(toolchain_bin, arch + '-nm')
|
||||
self.strip = os.path.join(toolchain_bin, arch + '-strip')
|
||||
|
||||
common_flags = ''
|
||||
common_flags = '-O2 -g'
|
||||
|
||||
if not x64:
|
||||
# enable SSE support which is required for LAME
|
||||
common_flags += ' -march=pentium3'
|
||||
|
||||
self.cflags = '-O2 -g ' + common_flags
|
||||
self.cxxflags = '-O2 -g ' + common_flags
|
||||
self.cflags = common_flags
|
||||
self.cxxflags = common_flags
|
||||
self.cppflags = '-isystem ' + os.path.join(install_prefix, 'include')
|
||||
self.ldflags = '-L' + os.path.join(install_prefix, 'lib')
|
||||
self.libs = ''
|
||||
|
Reference in New Issue
Block a user