Compare commits
218 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b5bd294e5c | ||
![]() |
ac60bd47f0 | ||
![]() |
b7248f0333 | ||
![]() |
8a5b5378e6 | ||
![]() |
4a49f75799 | ||
![]() |
9d2666f293 | ||
![]() |
e63fcc5982 | ||
![]() |
4c37c17f2e | ||
![]() |
722820a375 | ||
![]() |
688023eb9e | ||
![]() |
5771aeaddd | ||
![]() |
a42da90042 | ||
![]() |
d7d32ed6fc | ||
![]() |
4715acf27e | ||
![]() |
8780db5ee8 | ||
![]() |
b8bfc98618 | ||
![]() |
6e6f72a521 | ||
![]() |
a654c5d643 | ||
![]() |
c5d6aa169f | ||
![]() |
c1c67286d3 | ||
![]() |
2fb34697c7 | ||
![]() |
94b5b9f370 | ||
![]() |
a9467513e1 | ||
![]() |
17d944f6ce | ||
![]() |
0f82f18652 | ||
![]() |
3db3e577f1 | ||
![]() |
37ee821947 | ||
![]() |
916ab9a7e6 | ||
![]() |
1802cf9fd1 | ||
![]() |
1bf7d30623 | ||
![]() |
b2d89253a6 | ||
![]() |
50c1e3738a | ||
![]() |
7a939746ae | ||
![]() |
feac1a3f56 | ||
![]() |
f3c37e484e | ||
![]() |
49130c2018 | ||
![]() |
94af199c49 | ||
![]() |
2d25f6f57f | ||
![]() |
cf179ec294 | ||
![]() |
4d6f220a2f | ||
![]() |
0ffbe5b5ea | ||
![]() |
5b83c834ac | ||
![]() |
da7f32bddb | ||
![]() |
9a5eac4ea9 | ||
![]() |
6571b5d118 | ||
![]() |
12dff8e382 | ||
![]() |
c4da87a0cb | ||
![]() |
446f8f29d3 | ||
![]() |
48cc76f114 | ||
![]() |
a0892b852e | ||
![]() |
485c7805eb | ||
![]() |
23802f4489 | ||
![]() |
3fedd978a2 | ||
![]() |
a9f1bed922 | ||
![]() |
eb23788fec | ||
![]() |
f6d73555a6 | ||
![]() |
a56a709406 | ||
![]() |
5f253e66f6 | ||
![]() |
4669f7e2b9 | ||
![]() |
4c90f88704 | ||
![]() |
a7213b78d6 | ||
![]() |
719333e16e | ||
![]() |
100e471b49 | ||
![]() |
3f2016e552 | ||
![]() |
dd89ea4505 | ||
![]() |
101e12cf9a | ||
![]() |
f382808450 | ||
![]() |
0cbe3c2a93 | ||
![]() |
4f0ae28359 | ||
![]() |
6a4250f485 | ||
![]() |
3322b29e6a | ||
![]() |
33ac472601 | ||
![]() |
561d6fd478 | ||
![]() |
42a01822bf | ||
![]() |
38f1237d49 | ||
![]() |
8df77122e5 | ||
![]() |
fef6b9df80 | ||
![]() |
d52eac66db | ||
![]() |
70879f0abc | ||
![]() |
bcb393628e | ||
![]() |
18d3a5c12b | ||
![]() |
6ee3d0102b | ||
![]() |
fc9626e2f4 | ||
![]() |
3bedd94fc8 | ||
![]() |
8842650c33 | ||
![]() |
d5bf128cee | ||
![]() |
5cd86e272f | ||
![]() |
740cbe9e02 | ||
![]() |
ed890a273a | ||
![]() |
068cd559e1 | ||
![]() |
dc127f39a7 | ||
![]() |
7a99a7008c | ||
![]() |
70b451db7b | ||
![]() |
2ab03a0914 | ||
![]() |
2fa8c7d2db | ||
![]() |
7c759ba8b0 | ||
![]() |
6d9b452fde | ||
![]() |
f7eb1c9a83 | ||
![]() |
2d22e6dee4 | ||
![]() |
4587bf759d | ||
![]() |
e1e37cfe3c | ||
![]() |
381934985a | ||
![]() |
a8042885ac | ||
![]() |
a71e68db50 | ||
![]() |
1417578b3d | ||
![]() |
96befa138c | ||
![]() |
16a99804de | ||
![]() |
75a39ed279 | ||
![]() |
4d357ab77c | ||
![]() |
d4f3dd49b4 | ||
![]() |
4ec6d0555a | ||
![]() |
a6a1182c4c | ||
![]() |
a59c9c602b | ||
![]() |
0c4d824d64 | ||
![]() |
a5281856c9 | ||
![]() |
0206a46d39 | ||
![]() |
9475ef2202 | ||
![]() |
edae00e719 | ||
![]() |
fb695bc55f | ||
![]() |
23a5b8fd3c | ||
![]() |
273a93cfcf | ||
![]() |
d105985d78 | ||
![]() |
f8cfeb39e9 | ||
![]() |
d5d3982d3c | ||
![]() |
47341107ea | ||
![]() |
90eaa87a4d | ||
![]() |
b09a54b2c2 | ||
![]() |
10aec174d5 | ||
![]() |
d32ed194e8 | ||
![]() |
70d0fbd715 | ||
![]() |
302432e157 | ||
![]() |
4ab8a677dc | ||
![]() |
52e4a4c904 | ||
![]() |
a0f6932ebe | ||
![]() |
6e700dab69 | ||
![]() |
35eaed7206 | ||
![]() |
e7c963f2ce | ||
![]() |
949d72e368 | ||
![]() |
8d2a184658 | ||
![]() |
c877a32d97 | ||
![]() |
541468f0ca | ||
![]() |
d2797effa3 | ||
![]() |
1170fb1e1e | ||
![]() |
65b9b3195c | ||
![]() |
258830e913 | ||
![]() |
d91da96798 | ||
![]() |
b3897df682 | ||
![]() |
3cacb56bb7 | ||
![]() |
15a1973e28 | ||
![]() |
ad7d47a8ba | ||
![]() |
0948c607b6 | ||
![]() |
60d04052c5 | ||
![]() |
c1780ac657 | ||
![]() |
e49cf0ec38 | ||
![]() |
e1d641f684 | ||
![]() |
4efd0a9f77 | ||
![]() |
f6f8751332 | ||
![]() |
abb28593ce | ||
![]() |
115693b046 | ||
![]() |
e4b055eb6d | ||
![]() |
9866adff95 | ||
![]() |
a8b0c55818 | ||
![]() |
cac88e8be5 | ||
![]() |
e9f6a3482c | ||
![]() |
5d2e80f188 | ||
![]() |
cfd4d5b13e | ||
![]() |
06514aec63 | ||
![]() |
4ded1ae67b | ||
![]() |
1da974e3fa | ||
![]() |
94f06f0946 | ||
![]() |
d9eec8a455 | ||
![]() |
eaecbcafb2 | ||
![]() |
73b5d0a9b9 | ||
![]() |
c2d0f35e7a | ||
![]() |
ab99a57997 | ||
![]() |
c8ebaf3521 | ||
![]() |
52d00f7e30 | ||
![]() |
309491a6d8 | ||
![]() |
e7bfd32ccc | ||
![]() |
6f283b52ab | ||
![]() |
32bddfabea | ||
![]() |
1944c826bc | ||
![]() |
619bb60b26 | ||
![]() |
c549e16ed1 | ||
![]() |
01c9c4507f | ||
![]() |
8c9d7bf07e | ||
![]() |
44ef34db88 | ||
![]() |
5781f223f6 | ||
![]() |
e4c8ebe056 | ||
![]() |
76b25a1377 | ||
![]() |
ccc3ee663b | ||
![]() |
0626661764 | ||
![]() |
31db04a3ca | ||
![]() |
0c7163b9db | ||
![]() |
7d78cad8af | ||
![]() |
912530ed20 | ||
![]() |
d3f37199b9 | ||
![]() |
a4748d84b0 | ||
![]() |
8f847ec381 | ||
![]() |
3a70f09dd3 | ||
![]() |
568f63100b | ||
![]() |
3e25916b37 | ||
![]() |
5f9438dae6 | ||
![]() |
99e65c58ce | ||
![]() |
df71b07e9d | ||
![]() |
2694195215 | ||
![]() |
66450d1f3c | ||
![]() |
76efea3aa7 | ||
![]() |
7ab0dfc8ce | ||
![]() |
15ff7c4cad | ||
![]() |
9ab9b97f20 | ||
![]() |
88d92aceab | ||
![]() |
a2ce4352c8 | ||
![]() |
84f43ccde8 | ||
![]() |
38704c9cf3 | ||
![]() |
910d0ec92b | ||
![]() |
3b05c89765 | ||
![]() |
e77b3fa46f |
78
NEWS
78
NEWS
@@ -1,3 +1,81 @@
|
|||||||
|
ver 0.23.16 (2024/12/03)
|
||||||
|
* database
|
||||||
|
- fix integer overflows with 64-bit inode numbers
|
||||||
|
* filter
|
||||||
|
- ffmpeg: fix for filters producing no output
|
||||||
|
* support libfmt 11
|
||||||
|
* support ICU 76
|
||||||
|
|
||||||
|
ver 0.23.15 (2023/12/20)
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: fix build failure with FFmpeg 6.1
|
||||||
|
* output
|
||||||
|
- alsa: limit buffer time to 2 seconds
|
||||||
|
|
||||||
|
ver 0.23.14 (2023/10/08)
|
||||||
|
* decoder
|
||||||
|
- flac: fix scanning files with non-ASCII names on Windows
|
||||||
|
- mad: fix calculation of LAME peak values
|
||||||
|
* mixer
|
||||||
|
- wasapi: fix problem setting volume
|
||||||
|
* more libfmt 10 fixes
|
||||||
|
* fix auto-detected systemd unit directory
|
||||||
|
* Android
|
||||||
|
- require Android 7 or newer
|
||||||
|
|
||||||
|
ver 0.23.13 (2023/05/22)
|
||||||
|
* input
|
||||||
|
- curl: fix busy loop after connection failed
|
||||||
|
- curl: hide "404" log messages for non-existent ".mpdignore" files
|
||||||
|
* archive
|
||||||
|
- zzip: fix crash bug
|
||||||
|
* database
|
||||||
|
- simple: reveal hidden songs after deleting containing CUE
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: reorder to a lower priority than "gme"
|
||||||
|
- gme: require GME 0.6 or later
|
||||||
|
* output
|
||||||
|
- pipewire: fix corruption bug due to missing lock
|
||||||
|
* Linux
|
||||||
|
- shut down if parent process dies in --no-daemon mode
|
||||||
|
- determine systemd unit directories via pkg-config
|
||||||
|
* support libfmt 10
|
||||||
|
|
||||||
|
ver 0.23.12 (2023/01/17)
|
||||||
|
* input
|
||||||
|
- curl: require CURL 7.55.0 or later
|
||||||
|
* decoder
|
||||||
|
- mad: fix integer underflow with very small files
|
||||||
|
* tags
|
||||||
|
- fix crash bug due to race condition
|
||||||
|
* output
|
||||||
|
- pipewire: adjust to PipeWire 0.3.64 API change
|
||||||
|
* fix build failures with GCC 13
|
||||||
|
|
||||||
|
ver 0.23.11 (2022/11/28)
|
||||||
|
* database
|
||||||
|
- simple: move default database to ~/.cache/mpd/db from ~/.cache/mpd.db
|
||||||
|
- simple: default "cache_directory" to ~/.cache/mpd/mounts
|
||||||
|
* macOS: fix build failure "no archive members specified"
|
||||||
|
* Windows
|
||||||
|
- fix crash bug (stack buffer overflow) after I/O errors
|
||||||
|
- fix path traversal bug because backslash was allowed in playlist names
|
||||||
|
* Android/Windows
|
||||||
|
- update OpenSSL to 3.0.7
|
||||||
|
- re-enable CURL's verbose error strings
|
||||||
|
|
||||||
|
ver 0.23.10 (2022/10/14)
|
||||||
|
* storage
|
||||||
|
- curl: fix file time stamps
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: fix libfmt 9 compiler warning
|
||||||
|
* encoder
|
||||||
|
- flac: fix failure when libFLAC is built without Ogg support
|
||||||
|
* output
|
||||||
|
- alsa: fix crash bug
|
||||||
|
* Windows
|
||||||
|
- log to stdout by default, don't require "log_file" setting
|
||||||
|
|
||||||
ver 0.23.9 (2022/08/18)
|
ver 0.23.9 (2022/08/18)
|
||||||
* input
|
* input
|
||||||
- cdio_paranoia: add options "mode" and "skip"
|
- cdio_paranoia: add options "mode" and "skip"
|
||||||
|
@@ -2,10 +2,10 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.musicpd"
|
package="org.musicpd"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:versionCode="68"
|
android:versionCode="74"
|
||||||
android:versionName="0.23.9">
|
android:versionName="0.23.16">
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30"/>
|
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30"/>
|
||||||
|
|
||||||
<uses-feature android:name="android.software.leanback"
|
<uses-feature android:name="android.software.leanback"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
127
android/build.py
127
android/build.py
@@ -20,130 +20,13 @@ if not os.path.isdir(ndk_path):
|
|||||||
print("NDK not found in", ndk_path, file=sys.stderr)
|
print("NDK not found in", ndk_path, file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
android_abis = {
|
|
||||||
'armeabi-v7a': {
|
|
||||||
'arch': 'arm-linux-androideabi',
|
|
||||||
'ndk_arch': 'arm',
|
|
||||||
'llvm_triple': 'armv7-linux-androideabi',
|
|
||||||
'cflags': '-fpic -mfpu=neon -mfloat-abi=softfp',
|
|
||||||
},
|
|
||||||
|
|
||||||
'arm64-v8a': {
|
|
||||||
'arch': 'aarch64-linux-android',
|
|
||||||
'ndk_arch': 'arm64',
|
|
||||||
'llvm_triple': 'aarch64-linux-android',
|
|
||||||
'cflags': '-fpic',
|
|
||||||
},
|
|
||||||
|
|
||||||
'x86': {
|
|
||||||
'arch': 'i686-linux-android',
|
|
||||||
'ndk_arch': 'x86',
|
|
||||||
'llvm_triple': 'i686-linux-android',
|
|
||||||
'cflags': '-fPIC -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
|
|
||||||
},
|
|
||||||
|
|
||||||
'x86_64': {
|
|
||||||
'arch': 'x86_64-linux-android',
|
|
||||||
'ndk_arch': 'x86_64',
|
|
||||||
'llvm_triple': 'x86_64-linux-android',
|
|
||||||
'cflags': '-fPIC -m64',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
# select the NDK target
|
|
||||||
abi_info = android_abis[android_abi]
|
|
||||||
arch = abi_info['arch']
|
|
||||||
|
|
||||||
# the path to the MPD sources
|
# the path to the MPD sources
|
||||||
mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..'))
|
mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..'))
|
||||||
sys.path[0] = os.path.join(mpd_path, 'python')
|
sys.path[0] = os.path.join(mpd_path, 'python')
|
||||||
|
|
||||||
# output directories
|
# output directories
|
||||||
from build.dirs import lib_path, tarball_path, src_path
|
from build.dirs import lib_path, tarball_path, src_path
|
||||||
from build.meson import configure as run_meson
|
from build.toolchain import AndroidNdkToolchain
|
||||||
|
|
||||||
arch_path = os.path.join(lib_path, arch)
|
|
||||||
build_path = os.path.join(arch_path, 'build')
|
|
||||||
|
|
||||||
# build host configuration
|
|
||||||
build_arch = 'linux-x86_64'
|
|
||||||
|
|
||||||
# set up the NDK toolchain
|
|
||||||
|
|
||||||
class AndroidNdkToolchain:
|
|
||||||
def __init__(self, tarball_path, src_path, build_path,
|
|
||||||
use_cxx):
|
|
||||||
self.tarball_path = tarball_path
|
|
||||||
self.src_path = src_path
|
|
||||||
self.build_path = build_path
|
|
||||||
|
|
||||||
ndk_arch = abi_info['ndk_arch']
|
|
||||||
android_api_level = '21'
|
|
||||||
|
|
||||||
install_prefix = os.path.join(arch_path, 'root')
|
|
||||||
|
|
||||||
self.arch = arch
|
|
||||||
self.actual_arch = arch
|
|
||||||
self.install_prefix = install_prefix
|
|
||||||
|
|
||||||
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
|
|
||||||
llvm_triple = abi_info['llvm_triple'] + android_api_level
|
|
||||||
|
|
||||||
common_flags = '-Os -g'
|
|
||||||
common_flags += ' ' + abi_info['cflags']
|
|
||||||
|
|
||||||
llvm_bin = os.path.join(llvm_path, 'bin')
|
|
||||||
self.cc = os.path.join(llvm_bin, 'clang')
|
|
||||||
self.cxx = os.path.join(llvm_bin, 'clang++')
|
|
||||||
common_flags += ' -target ' + llvm_triple
|
|
||||||
|
|
||||||
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
|
|
||||||
|
|
||||||
self.ar = os.path.join(llvm_bin, 'llvm-ar')
|
|
||||||
self.ranlib = os.path.join(llvm_bin, 'llvm-ranlib')
|
|
||||||
self.nm = os.path.join(llvm_bin, 'llvm-nm')
|
|
||||||
self.strip = os.path.join(llvm_bin, 'llvm-strip')
|
|
||||||
|
|
||||||
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') + \
|
|
||||||
' -Wl,--exclude-libs=ALL' + \
|
|
||||||
' ' + common_flags
|
|
||||||
self.ldflags = common_flags
|
|
||||||
self.libs = ''
|
|
||||||
|
|
||||||
self.is_arm = ndk_arch == 'arm'
|
|
||||||
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
|
||||||
self.is_aarch64 = ndk_arch == 'arm64'
|
|
||||||
self.is_windows = False
|
|
||||||
|
|
||||||
libstdcxx_flags = ''
|
|
||||||
libstdcxx_cxxflags = ''
|
|
||||||
libstdcxx_ldflags = ''
|
|
||||||
libstdcxx_libs = '-static-libstdc++'
|
|
||||||
|
|
||||||
if self.is_armv7:
|
|
||||||
# On 32 bit ARM, clang generates no ".eh_frame" section;
|
|
||||||
# instead, the LLVM unwinder library is used for unwinding
|
|
||||||
# the stack after a C++ exception was thrown
|
|
||||||
libstdcxx_libs += ' -lunwind'
|
|
||||||
|
|
||||||
if use_cxx:
|
|
||||||
self.cxxflags += ' ' + libstdcxx_cxxflags
|
|
||||||
self.ldflags += ' ' + libstdcxx_ldflags
|
|
||||||
self.libs += ' ' + libstdcxx_libs
|
|
||||||
|
|
||||||
self.env = dict(os.environ)
|
|
||||||
|
|
||||||
# redirect pkg-config to use our root directory instead of the
|
|
||||||
# default one on the build host
|
|
||||||
import shutil
|
|
||||||
bin_dir = os.path.join(install_prefix, 'bin')
|
|
||||||
os.makedirs(bin_dir, exist_ok=True)
|
|
||||||
self.pkg_config = shutil.copy(os.path.join(mpd_path, 'build', 'pkg-config.sh'),
|
|
||||||
os.path.join(bin_dir, 'pkg-config'))
|
|
||||||
self.env['PKG_CONFIG'] = self.pkg_config
|
|
||||||
|
|
||||||
# a list of third-party libraries to be used by MPD on Android
|
# a list of third-party libraries to be used by MPD on Android
|
||||||
from build.libs import *
|
from build.libs import *
|
||||||
@@ -165,13 +48,17 @@ thirdparty_libs = [
|
|||||||
|
|
||||||
# build the third-party libraries
|
# build the third-party libraries
|
||||||
for x in thirdparty_libs:
|
for x in thirdparty_libs:
|
||||||
toolchain = AndroidNdkToolchain(tarball_path, src_path, build_path,
|
toolchain = AndroidNdkToolchain(mpd_path, lib_path,
|
||||||
|
tarball_path, src_path,
|
||||||
|
ndk_path, android_abi,
|
||||||
use_cxx=x.use_cxx)
|
use_cxx=x.use_cxx)
|
||||||
if not x.is_installed(toolchain):
|
if not x.is_installed(toolchain):
|
||||||
x.build(toolchain)
|
x.build(toolchain)
|
||||||
|
|
||||||
# configure and build MPD
|
# configure and build MPD
|
||||||
toolchain = AndroidNdkToolchain(tarball_path, src_path, build_path,
|
toolchain = AndroidNdkToolchain(mpd_path, lib_path,
|
||||||
|
tarball_path, src_path,
|
||||||
|
ndk_path, android_abi,
|
||||||
use_cxx=True)
|
use_cxx=True)
|
||||||
|
|
||||||
configure_args += [
|
configure_args += [
|
||||||
|
@@ -38,7 +38,10 @@ author = 'Max Kellermann'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.23.9'
|
with open('../meson.build') as f:
|
||||||
|
import re
|
||||||
|
version = re.match(r"project\([^\)]*\bversion:\s*'([^']+)'",
|
||||||
|
f.read(4096)).group(1)
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
#release = version + '~git'
|
#release = version + '~git'
|
||||||
|
|
||||||
@@ -47,7 +50,7 @@ version = '0.23.9'
|
|||||||
#
|
#
|
||||||
# This is also used if you do content translation via gettext catalogs.
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
# Usually you set "language" from the command line for these cases.
|
# Usually you set "language" from the command line for these cases.
|
||||||
language = None
|
language = "en"
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
# non-false value, then it is used:
|
# non-false value, then it is used:
|
||||||
|
@@ -20,6 +20,7 @@ Some example code:
|
|||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
|
int
|
||||||
Foo(const char *abc, int xyz)
|
Foo(const char *abc, int xyz)
|
||||||
{
|
{
|
||||||
if (abc == nullptr) {
|
if (abc == nullptr) {
|
||||||
|
@@ -11,6 +11,12 @@ Music Player Daemon
|
|||||||
client
|
client
|
||||||
protocol
|
protocol
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: man pages:
|
||||||
|
|
||||||
|
mpd.1
|
||||||
|
mpd.conf.5
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
==================
|
||||||
|
@@ -181,7 +181,7 @@
|
|||||||
#
|
#
|
||||||
#database {
|
#database {
|
||||||
# plugin "simple"
|
# plugin "simple"
|
||||||
# path "~/.local/share/mpd/db
|
# path "~/.local/share/mpd/db"
|
||||||
# cache_directory "~/.local/share/mpd/cache"
|
# cache_directory "~/.local/share/mpd/cache"
|
||||||
#}
|
#}
|
||||||
#
|
#
|
||||||
@@ -314,6 +314,7 @@ input {
|
|||||||
## device "Digital Audio (S/PDIF) (High Definition Audio Device)" # optional
|
## device "Digital Audio (S/PDIF) (High Definition Audio Device)" # optional
|
||||||
# or
|
# or
|
||||||
## device "0" # optional
|
## device "0" # optional
|
||||||
|
## mixer_type "hardware" # optional
|
||||||
## Exclusive mode blocks all other audio source, and get best audio quality without resampling.
|
## Exclusive mode blocks all other audio source, and get best audio quality without resampling.
|
||||||
## exclusive "no" # optional
|
## exclusive "no" # optional
|
||||||
## Enumerate all devices in log.
|
## Enumerate all devices in log.
|
||||||
|
@@ -219,8 +219,9 @@ Opens remote files or streams over HTTP using libcurl.
|
|||||||
|
|
||||||
Note that unless overridden by the below settings (e.g. by setting
|
Note that unless overridden by the below settings (e.g. by setting
|
||||||
them to a blank value), general curl configuration from environment
|
them to a blank value), general curl configuration from environment
|
||||||
variables such as ``http_proxy`` or specified in :file:`~/.curlrc`
|
variables such as ``http_proxy`` will be in effect.
|
||||||
will be in effect.
|
|
||||||
|
User name and password are read from an optional :file:`~/.netrc`, :file:`~/.curlrc` is not read.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
:widths: 20 80
|
:widths: 20 80
|
||||||
@@ -1114,7 +1115,7 @@ Connect to a `PipeWire <https://pipewire.org/>`_ server. Requires
|
|||||||
* - **target NAME**
|
* - **target NAME**
|
||||||
- Link to the given target. If not specified, let the PipeWire
|
- Link to the given target. If not specified, let the PipeWire
|
||||||
manager select a target. To get a list of available targets,
|
manager select a target. To get a list of available targets,
|
||||||
type ``pw-cli dump short Node``
|
type ``pw-cli ls Node``
|
||||||
* - **remote NAME**
|
* - **remote NAME**
|
||||||
- The name of the remote to connect to. The default is
|
- The name of the remote to connect to. The default is
|
||||||
``pipewire-0``.
|
``pipewire-0``.
|
||||||
|
@@ -691,7 +691,8 @@ Song ids on the other hand are stable: an id is assigned to a song
|
|||||||
when it is added, and will stay the same, no matter how much it is
|
when it is added, and will stay the same, no matter how much it is
|
||||||
moved around. Adding the same song twice will assign different ids to
|
moved around. Adding the same song twice will assign different ids to
|
||||||
them, and a deleted-and-readded song will have a new id. This way, a
|
them, and a deleted-and-readded song will have a new id. This way, a
|
||||||
client can always be sure the correct song is being used.
|
client can always be sure the correct song is being used. Song ids are not
|
||||||
|
preserved across :program:`MPD` restarts.
|
||||||
|
|
||||||
Many commands come in two flavors, one for each address type.
|
Many commands come in two flavors, one for each address type.
|
||||||
Whenever possible, ids should be used.
|
Whenever possible, ids should be used.
|
||||||
|
@@ -199,7 +199,7 @@ Compiling for Android
|
|||||||
You need:
|
You need:
|
||||||
|
|
||||||
* Android SDK
|
* Android SDK
|
||||||
* `Android NDK r23 <https://developer.android.com/ndk/downloads>`_
|
* `Android NDK r25b <https://developer.android.com/ndk/downloads>`_
|
||||||
* `Meson 0.56.0 <http://mesonbuild.com/>`__ and `Ninja
|
* `Meson 0.56.0 <http://mesonbuild.com/>`__ and `Ninja
|
||||||
<https://ninja-build.org/>`__
|
<https://ninja-build.org/>`__
|
||||||
* cmake
|
* cmake
|
||||||
@@ -611,6 +611,11 @@ If ReplayGain is enabled, then the setting ``replaygain_preamp`` is
|
|||||||
set to a value (in dB) between ``-15`` and ``15``. This is the gain
|
set to a value (in dB) between ``-15`` and ``15``. This is the gain
|
||||||
applied to songs with ReplayGain tags.
|
applied to songs with ReplayGain tags.
|
||||||
|
|
||||||
|
On songs without ReplayGain tags, the setting
|
||||||
|
``replaygain_missing_preamp`` is used instead. If this setting is not
|
||||||
|
configured, then no ReplayGain is applied to such songs, and they will
|
||||||
|
appear too loud.
|
||||||
|
|
||||||
ReplayGain is usually implemented with a software volume filter (which
|
ReplayGain is usually implemented with a software volume filter (which
|
||||||
prevents `Bit-perfect playback`_). To use a hardware mixer, set
|
prevents `Bit-perfect playback`_). To use a hardware mixer, set
|
||||||
``replay_gain_handler`` to ``mixer`` in the ``audio_output`` section
|
``replay_gain_handler`` to ``mixer`` in the ``audio_output`` section
|
||||||
@@ -656,9 +661,11 @@ MPD enables MixRamp if:
|
|||||||
- Cross-fade is enabled
|
- Cross-fade is enabled
|
||||||
- :ref:`mixrampdelay <command_mixrampdelay>` is set to a positive
|
- :ref:`mixrampdelay <command_mixrampdelay>` is set to a positive
|
||||||
value, e.g.::
|
value, e.g.::
|
||||||
|
|
||||||
mpc mixrampdelay 1
|
mpc mixrampdelay 1
|
||||||
- :ref:`mixrampdb <command_mixrampdb>` is set to a reasonable value,
|
- :ref:`mixrampdb <command_mixrampdb>` is set to a reasonable value,
|
||||||
e.g.::
|
e.g.::
|
||||||
|
|
||||||
mpc mixrampdb -17
|
mpc mixrampdb -17
|
||||||
- both songs have MixRamp tags
|
- both songs have MixRamp tags
|
||||||
- both songs have the same audio format (or :ref:`audio_output_format`
|
- both songs have the same audio format (or :ref:`audio_output_format`
|
||||||
|
15
meson.build
15
meson.build
@@ -1,7 +1,7 @@
|
|||||||
project(
|
project(
|
||||||
'mpd',
|
'mpd',
|
||||||
['c', 'cpp'],
|
['c', 'cpp'],
|
||||||
version: '0.23.9',
|
version: '0.23.16',
|
||||||
meson_version: '>= 0.56.0',
|
meson_version: '>= 0.56.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
@@ -76,6 +76,9 @@ test_common_flags = [
|
|||||||
|
|
||||||
# suppress bogus GCC12 warnings in libfmt headers
|
# suppress bogus GCC12 warnings in libfmt headers
|
||||||
'-Wno-stringop-overflow',
|
'-Wno-stringop-overflow',
|
||||||
|
|
||||||
|
# libfmt causes this warning due to -ffast-math
|
||||||
|
'-Wno-nan-infinity-disabled',
|
||||||
]
|
]
|
||||||
|
|
||||||
test_global_cxxflags = test_global_common_flags + [
|
test_global_cxxflags = test_global_common_flags + [
|
||||||
@@ -205,7 +208,6 @@ enable_daemon = not is_windows and not is_android and get_option('daemon')
|
|||||||
conf.set('ENABLE_DAEMON', enable_daemon)
|
conf.set('ENABLE_DAEMON', enable_daemon)
|
||||||
|
|
||||||
conf.set('HAVE_GETPWNAM_R', compiler.has_function('getpwnam_r'))
|
conf.set('HAVE_GETPWNAM_R', compiler.has_function('getpwnam_r'))
|
||||||
conf.set('HAVE_GETPWUID_R', compiler.has_function('getpwuid_r'))
|
|
||||||
conf.set('HAVE_INITGROUPS', compiler.has_function('initgroups'))
|
conf.set('HAVE_INITGROUPS', compiler.has_function('initgroups'))
|
||||||
conf.set('HAVE_FNMATCH', compiler.has_function('fnmatch'))
|
conf.set('HAVE_FNMATCH', compiler.has_function('fnmatch'))
|
||||||
|
|
||||||
@@ -251,6 +253,14 @@ endif
|
|||||||
|
|
||||||
fmt_dep = dependency('fmt', fallback: ['fmt', 'fmt_dep'])
|
fmt_dep = dependency('fmt', fallback: ['fmt', 'fmt_dep'])
|
||||||
|
|
||||||
|
if compiler.get_id() == 'clang' and compiler.version().version_compare('<15')
|
||||||
|
fmt_dep = declare_dependency(
|
||||||
|
dependencies: fmt_dep,
|
||||||
|
# suppress bogus clang 14 warning (the version in Android NDK r25b)
|
||||||
|
compile_args: ['-Wno-unused-local-typedef'],
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
log = static_library(
|
log = static_library(
|
||||||
'log',
|
'log',
|
||||||
'src/Log.cxx',
|
'src/Log.cxx',
|
||||||
@@ -382,6 +392,7 @@ endif
|
|||||||
|
|
||||||
if enable_database
|
if enable_database
|
||||||
sources += [
|
sources += [
|
||||||
|
'src/storage/StorageState.cxx',
|
||||||
'src/queue/PlaylistUpdate.cxx',
|
'src/queue/PlaylistUpdate.cxx',
|
||||||
'src/command/StorageCommands.cxx',
|
'src/command/StorageCommands.cxx',
|
||||||
'src/command/DatabaseCommands.cxx',
|
'src/command/DatabaseCommands.cxx',
|
||||||
|
@@ -1,26 +1,32 @@
|
|||||||
import os.path, subprocess, sys
|
import os.path, subprocess, sys
|
||||||
|
from typing import Collection, Iterable, Optional, Sequence, Union
|
||||||
|
from collections.abc import Mapping
|
||||||
|
|
||||||
from build.makeproject import MakeProject
|
from build.makeproject import MakeProject
|
||||||
|
from .toolchain import AnyToolchain
|
||||||
|
|
||||||
class AutotoolsProject(MakeProject):
|
class AutotoolsProject(MakeProject):
|
||||||
def __init__(self, url, md5, installed, configure_args=[],
|
def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
|
||||||
autogen=False,
|
configure_args: Iterable[str]=[],
|
||||||
autoreconf=False,
|
autogen: bool=False,
|
||||||
cppflags='',
|
autoreconf: bool=False,
|
||||||
ldflags='',
|
per_arch_cflags: Optional[Mapping[str, str]]=None,
|
||||||
libs='',
|
cppflags: str='',
|
||||||
subdirs=None,
|
ldflags: str='',
|
||||||
|
libs: str='',
|
||||||
|
subdirs: Optional[Collection[str]]=None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
MakeProject.__init__(self, url, md5, installed, **kwargs)
|
MakeProject.__init__(self, url, md5, installed, **kwargs)
|
||||||
self.configure_args = configure_args
|
self.configure_args = configure_args
|
||||||
self.autogen = autogen
|
self.autogen = autogen
|
||||||
self.autoreconf = autoreconf
|
self.autoreconf = autoreconf
|
||||||
|
self.per_arch_cflags = per_arch_cflags
|
||||||
self.cppflags = cppflags
|
self.cppflags = cppflags
|
||||||
self.ldflags = ldflags
|
self.ldflags = ldflags
|
||||||
self.libs = libs
|
self.libs = libs
|
||||||
self.subdirs = subdirs
|
self.subdirs = subdirs
|
||||||
|
|
||||||
def configure(self, toolchain):
|
def configure(self, toolchain: AnyToolchain) -> str:
|
||||||
src = self.unpack(toolchain)
|
src = self.unpack(toolchain)
|
||||||
if self.autogen:
|
if self.autogen:
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
@@ -35,27 +41,48 @@ class AutotoolsProject(MakeProject):
|
|||||||
|
|
||||||
build = self.make_build_path(toolchain)
|
build = self.make_build_path(toolchain)
|
||||||
|
|
||||||
|
arch_cflags = ''
|
||||||
|
if self.per_arch_cflags is not None and toolchain.host_triplet is not None:
|
||||||
|
arch_cflags = self.per_arch_cflags.get(toolchain.host_triplet, '')
|
||||||
|
|
||||||
configure = [
|
configure = [
|
||||||
os.path.join(src, 'configure'),
|
os.path.join(src, 'configure'),
|
||||||
'CC=' + toolchain.cc,
|
'CC=' + toolchain.cc,
|
||||||
'CXX=' + toolchain.cxx,
|
'CXX=' + toolchain.cxx,
|
||||||
'CFLAGS=' + toolchain.cflags,
|
'CFLAGS=' + toolchain.cflags + ' ' + arch_cflags,
|
||||||
'CXXFLAGS=' + toolchain.cxxflags,
|
'CXXFLAGS=' + toolchain.cxxflags + ' ' + arch_cflags,
|
||||||
'CPPFLAGS=' + toolchain.cppflags + ' ' + self.cppflags,
|
'CPPFLAGS=' + toolchain.cppflags + ' ' + self.cppflags,
|
||||||
'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
|
'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
|
||||||
'LIBS=' + toolchain.libs + ' ' + self.libs,
|
'LIBS=' + toolchain.libs + ' ' + self.libs,
|
||||||
'AR=' + toolchain.ar,
|
'AR=' + toolchain.ar,
|
||||||
|
'ARFLAGS=' + toolchain.arflags,
|
||||||
'RANLIB=' + toolchain.ranlib,
|
'RANLIB=' + toolchain.ranlib,
|
||||||
'STRIP=' + toolchain.strip,
|
'STRIP=' + toolchain.strip,
|
||||||
'--host=' + toolchain.arch,
|
|
||||||
'--prefix=' + toolchain.install_prefix,
|
'--prefix=' + toolchain.install_prefix,
|
||||||
'--enable-silent-rules',
|
'--disable-silent-rules',
|
||||||
] + self.configure_args
|
]
|
||||||
|
|
||||||
|
if toolchain.host_triplet is not None:
|
||||||
|
configure.append('--host=' + toolchain.host_triplet)
|
||||||
|
|
||||||
|
configure.extend(self.configure_args)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(configure)
|
||||||
|
subprocess.check_call(configure, cwd=build, env=toolchain.env)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
# dump config.log after a failed configure run
|
||||||
|
try:
|
||||||
|
with open(os.path.join(build, 'config.log')) as f:
|
||||||
|
sys.stdout.write(f.read())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
# re-raise the exception
|
||||||
|
raise
|
||||||
|
|
||||||
subprocess.check_call(configure, cwd=build, env=toolchain.env)
|
|
||||||
return build
|
return build
|
||||||
|
|
||||||
def _build(self, toolchain):
|
def _build(self, toolchain: AnyToolchain) -> None:
|
||||||
build = self.configure(toolchain)
|
build = self.configure(toolchain)
|
||||||
if self.subdirs is not None:
|
if self.subdirs is not None:
|
||||||
for subdir in self.subdirs:
|
for subdir in self.subdirs:
|
||||||
|
@@ -1,17 +1,21 @@
|
|||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from typing import cast, Optional, Sequence, TextIO, Union
|
||||||
|
from collections.abc import Mapping
|
||||||
|
|
||||||
from build.project import Project
|
from build.project import Project
|
||||||
|
from .toolchain import AnyToolchain
|
||||||
|
|
||||||
def __write_cmake_compiler(f, language, compiler):
|
def __write_cmake_compiler(f: TextIO, language: str, compiler: str) -> None:
|
||||||
s = compiler.split(' ', 1)
|
s = compiler.split(' ', 1)
|
||||||
if len(s) == 2:
|
if len(s) == 2:
|
||||||
print(f'set(CMAKE_{language}_COMPILER_LAUNCHER {s[0]})', file=f)
|
print(f'set(CMAKE_{language}_COMPILER_LAUNCHER {s[0]})', file=f)
|
||||||
compiler = s[1]
|
compiler = s[1]
|
||||||
print(f'set(CMAKE_{language}_COMPILER {compiler})', file=f)
|
print(f'set(CMAKE_{language}_COMPILER {compiler})', file=f)
|
||||||
|
|
||||||
def __write_cmake_toolchain_file(f, toolchain):
|
def __write_cmake_toolchain_file(f: TextIO, toolchain: AnyToolchain) -> None:
|
||||||
if '-darwin' in toolchain.actual_arch:
|
if toolchain.is_darwin:
|
||||||
cmake_system_name = 'Darwin'
|
cmake_system_name = 'Darwin'
|
||||||
elif toolchain.is_windows:
|
elif toolchain.is_windows:
|
||||||
cmake_system_name = 'Windows'
|
cmake_system_name = 'Windows'
|
||||||
@@ -20,67 +24,107 @@ def __write_cmake_toolchain_file(f, toolchain):
|
|||||||
|
|
||||||
f.write(f"""
|
f.write(f"""
|
||||||
set(CMAKE_SYSTEM_NAME {cmake_system_name})
|
set(CMAKE_SYSTEM_NAME {cmake_system_name})
|
||||||
set(CMAKE_SYSTEM_PROCESSOR {toolchain.actual_arch.split('-', 1)[0]})
|
set(CMAKE_SYSTEM_PROCESSOR {toolchain.host_triplet.split('-', 1)[0]})
|
||||||
|
|
||||||
set(CMAKE_C_COMPILER_TARGET {toolchain.actual_arch})
|
set(CMAKE_C_COMPILER_TARGET {toolchain.host_triplet})
|
||||||
set(CMAKE_CXX_COMPILER_TARGET {toolchain.actual_arch})
|
set(CMAKE_CXX_COMPILER_TARGET {toolchain.host_triplet})
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "{toolchain.cflags} {toolchain.cppflags}")
|
set(CMAKE_C_FLAGS_INIT "{toolchain.cflags} {toolchain.cppflags}")
|
||||||
set(CMAKE_CXX_FLAGS "{toolchain.cxxflags} {toolchain.cppflags}")
|
set(CMAKE_CXX_FLAGS_INIT "{toolchain.cxxflags} {toolchain.cppflags}")
|
||||||
""")
|
""")
|
||||||
__write_cmake_compiler(f, 'C', toolchain.cc)
|
__write_cmake_compiler(f, 'C', toolchain.cc)
|
||||||
__write_cmake_compiler(f, 'CXX', toolchain.cxx)
|
__write_cmake_compiler(f, 'CXX', toolchain.cxx)
|
||||||
|
|
||||||
def configure(toolchain, src, build, args=()):
|
if cmake_system_name == 'Darwin':
|
||||||
cross_args = []
|
# On macOS, cmake forcibly adds an "-isysroot" flag even if
|
||||||
|
# one is already present in the flags variable; this breaks
|
||||||
|
# cross-compiling for iOS, and can be worked around by setting
|
||||||
|
# the CMAKE_OSX_SYSROOT variable
|
||||||
|
# (https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_SYSROOT.html).
|
||||||
|
m = re.search(r'-isysroot +(\S+)', toolchain.cflags)
|
||||||
|
if m:
|
||||||
|
sysroot = m.group(1)
|
||||||
|
|
||||||
|
print(f'set(CMAKE_OSX_SYSROOT {sysroot})', file=f)
|
||||||
|
|
||||||
|
# search libraries and headers only in the sysroot, not on
|
||||||
|
# the build host
|
||||||
|
f.write(f"""
|
||||||
|
set(CMAKE_FIND_ROOT_PATH "{toolchain.install_prefix};{sysroot}")
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
""")
|
||||||
|
elif cmake_system_name == 'Windows':
|
||||||
|
# search libraries and headers only in the sysroot, not on
|
||||||
|
# the build host
|
||||||
|
f.write(f"""
|
||||||
|
set(CMAKE_FIND_ROOT_PATH "{toolchain.install_prefix}")
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
""")
|
||||||
|
|
||||||
|
def configure(toolchain: AnyToolchain, src: str, build: str, args: list[str]=[], env: Optional[Mapping[str, str]]=None) -> None:
|
||||||
|
cross_args: list[str] = []
|
||||||
|
|
||||||
if toolchain.is_windows:
|
if toolchain.is_windows:
|
||||||
cross_args.append('-DCMAKE_RC_COMPILER=' + toolchain.windres)
|
cross_args.append('-DCMAKE_RC_COMPILER=' + cast(str, toolchain.windres))
|
||||||
|
|
||||||
# Several targets need a sysroot to prevent pkg-config from
|
|
||||||
# looking for libraries on the build host (TODO: fix this
|
|
||||||
# properly); but we must not do that on Android because the NDK
|
|
||||||
# has a sysroot already
|
|
||||||
if '-android' not in toolchain.actual_arch and '-darwin' not in toolchain.actual_arch:
|
|
||||||
cross_args.append('-DCMAKE_SYSROOT=' + toolchain.install_prefix)
|
|
||||||
|
|
||||||
os.makedirs(build, exist_ok=True)
|
|
||||||
cmake_toolchain_file = os.path.join(build, 'cmake_toolchain_file')
|
|
||||||
with open(cmake_toolchain_file, 'w') as f:
|
|
||||||
__write_cmake_toolchain_file(f, toolchain)
|
|
||||||
|
|
||||||
configure = [
|
configure = [
|
||||||
'cmake',
|
'cmake',
|
||||||
src,
|
src,
|
||||||
|
|
||||||
'-DCMAKE_TOOLCHAIN_FILE=' + cmake_toolchain_file,
|
|
||||||
|
|
||||||
'-DCMAKE_INSTALL_PREFIX=' + toolchain.install_prefix,
|
'-DCMAKE_INSTALL_PREFIX=' + toolchain.install_prefix,
|
||||||
'-DCMAKE_BUILD_TYPE=release',
|
'-DCMAKE_BUILD_TYPE=release',
|
||||||
|
|
||||||
'-GNinja',
|
'-GNinja',
|
||||||
] + cross_args + args
|
] + cross_args + args
|
||||||
|
|
||||||
subprocess.check_call(configure, env=toolchain.env, cwd=build)
|
if toolchain.host_triplet is not None:
|
||||||
|
# cross-compiling: write a toolchain file
|
||||||
|
os.makedirs(build, exist_ok=True)
|
||||||
|
|
||||||
|
# Several targets need a sysroot to prevent pkg-config from
|
||||||
|
# looking for libraries on the build host (TODO: fix this
|
||||||
|
# properly); but we must not do that on Android because the NDK
|
||||||
|
# has a sysroot already
|
||||||
|
if not toolchain.is_android and not toolchain.is_darwin:
|
||||||
|
cross_args.append('-DCMAKE_SYSROOT=' + toolchain.install_prefix)
|
||||||
|
|
||||||
|
cmake_toolchain_file = os.path.join(build, 'cmake_toolchain_file')
|
||||||
|
with open(cmake_toolchain_file, 'w') as f:
|
||||||
|
__write_cmake_toolchain_file(f, toolchain)
|
||||||
|
|
||||||
|
configure.append('-DCMAKE_TOOLCHAIN_FILE=' + cmake_toolchain_file)
|
||||||
|
|
||||||
|
if env is None:
|
||||||
|
env = toolchain.env
|
||||||
|
else:
|
||||||
|
env = {**toolchain.env, **env}
|
||||||
|
|
||||||
|
print(configure)
|
||||||
|
subprocess.check_call(configure, env=env, cwd=build)
|
||||||
|
|
||||||
class CmakeProject(Project):
|
class CmakeProject(Project):
|
||||||
def __init__(self, url, md5, installed, configure_args=[],
|
def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
|
||||||
windows_configure_args=[],
|
configure_args: list[str]=[],
|
||||||
|
windows_configure_args: list[str]=[],
|
||||||
|
env: Optional[Mapping[str, str]]=None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
Project.__init__(self, url, md5, installed, **kwargs)
|
Project.__init__(self, url, md5, installed, **kwargs)
|
||||||
self.configure_args = configure_args
|
self.configure_args = configure_args
|
||||||
self.windows_configure_args = windows_configure_args
|
self.windows_configure_args = windows_configure_args
|
||||||
|
self.env = env
|
||||||
|
|
||||||
def configure(self, toolchain):
|
def configure(self, toolchain: AnyToolchain) -> str:
|
||||||
src = self.unpack(toolchain)
|
src = self.unpack(toolchain)
|
||||||
build = self.make_build_path(toolchain)
|
build = self.make_build_path(toolchain)
|
||||||
configure_args = self.configure_args
|
configure_args = self.configure_args
|
||||||
if toolchain.is_windows:
|
if toolchain.is_windows:
|
||||||
configure_args = configure_args + self.windows_configure_args
|
configure_args = configure_args + self.windows_configure_args
|
||||||
configure(toolchain, src, build, configure_args)
|
configure(toolchain, src, build, configure_args, self.env)
|
||||||
return build
|
return build
|
||||||
|
|
||||||
def _build(self, toolchain):
|
def _build(self, toolchain: AnyToolchain) -> None:
|
||||||
build = self.configure(toolchain)
|
build = self.configure(toolchain)
|
||||||
subprocess.check_call(['ninja', 'install'],
|
subprocess.check_call(['ninja', '-v', 'install'],
|
||||||
cwd=build, env=toolchain.env)
|
cwd=build, env=toolchain.env)
|
||||||
|
@@ -1,12 +1,50 @@
|
|||||||
from build.verify import verify_file_digest
|
from typing import Sequence, Union
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
def download_and_verify(url, md5, parent_path):
|
from .verify import verify_file_digest
|
||||||
|
|
||||||
|
def __to_string_sequence(x: Union[str, Sequence[str]]) -> Sequence[str]:
|
||||||
|
if isinstance(x, str):
|
||||||
|
return (x,)
|
||||||
|
else:
|
||||||
|
return x
|
||||||
|
|
||||||
|
def __get_any(x: Union[str, Sequence[str]]) -> str:
|
||||||
|
if isinstance(x, str):
|
||||||
|
return x
|
||||||
|
else:
|
||||||
|
return x[0]
|
||||||
|
|
||||||
|
def __download_one(url: str, path: str) -> None:
|
||||||
|
print("download", url)
|
||||||
|
urllib.request.urlretrieve(url, path)
|
||||||
|
|
||||||
|
def __download(urls: Sequence[str], path: str) -> None:
|
||||||
|
for url in urls[:-1]:
|
||||||
|
try:
|
||||||
|
__download_one(url, path)
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
print("download error:", sys.exc_info()[0])
|
||||||
|
__download_one(urls[-1], path)
|
||||||
|
|
||||||
|
def __download_and_verify_to(urls: Sequence[str], md5: str, path: str) -> None:
|
||||||
|
__download(urls, path)
|
||||||
|
if not verify_file_digest(path, md5):
|
||||||
|
raise RuntimeError("Digest mismatch")
|
||||||
|
|
||||||
|
def download_basename(urls: Union[str, Sequence[str]]) -> str:
|
||||||
|
return os.path.basename(__get_any(urls))
|
||||||
|
|
||||||
|
def download_and_verify(urls: Union[str, Sequence[str]], md5: str, parent_path: str) -> str:
|
||||||
"""Download a file, verify its MD5 checksum and return the local path."""
|
"""Download a file, verify its MD5 checksum and return the local path."""
|
||||||
|
|
||||||
|
base = download_basename(urls)
|
||||||
|
|
||||||
os.makedirs(parent_path, exist_ok=True)
|
os.makedirs(parent_path, exist_ok=True)
|
||||||
path = os.path.join(parent_path, os.path.basename(url))
|
path = os.path.join(parent_path, base)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if verify_file_digest(path, md5): return path
|
if verify_file_digest(path, md5): return path
|
||||||
@@ -16,11 +54,6 @@ def download_and_verify(url, md5, parent_path):
|
|||||||
|
|
||||||
tmp_path = path + '.tmp'
|
tmp_path = path + '.tmp'
|
||||||
|
|
||||||
print("download", url)
|
__download_and_verify_to(__to_string_sequence(urls), md5, tmp_path)
|
||||||
urllib.request.urlretrieve(url, tmp_path)
|
|
||||||
if not verify_file_digest(tmp_path, md5):
|
|
||||||
os.unlink(tmp_path)
|
|
||||||
raise RuntimeError("Digest mismatch")
|
|
||||||
|
|
||||||
os.rename(tmp_path, path)
|
os.rename(tmp_path, path)
|
||||||
return path
|
return path
|
||||||
|
@@ -29,8 +29,8 @@ libogg = CmakeProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
opus = AutotoolsProject(
|
opus = AutotoolsProject(
|
||||||
'https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz',
|
'https://downloads.xiph.org/releases/opus/opus-1.4.tar.gz',
|
||||||
'65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d',
|
'c9b32b4253be5ae63d1ff16eea06b94b5f0f2951b7a02aceef58e3a3ce49c51f',
|
||||||
'lib/libopus.a',
|
'lib/libopus.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -43,20 +43,23 @@ opus = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
flac = AutotoolsProject(
|
flac = AutotoolsProject(
|
||||||
'http://downloads.xiph.org/releases/flac/flac-1.3.4.tar.xz',
|
'http://downloads.xiph.org/releases/flac/flac-1.4.3.tar.xz',
|
||||||
'8ff0607e75a322dd7cd6ec48f4f225471404ae2730d0ea945127b1355155e737',
|
'6c58e69cd22348f441b861092b825e591d0b822e106de6eb0ee4d05d27205b70',
|
||||||
'lib/libFLAC.a',
|
'lib/libFLAC.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
|
'--disable-stack-smash-protection',
|
||||||
'--disable-xmms-plugin', '--disable-cpplibs',
|
'--disable-xmms-plugin', '--disable-cpplibs',
|
||||||
'--disable-doxygen-docs',
|
'--disable-doxygen-docs',
|
||||||
|
'--disable-programs',
|
||||||
],
|
],
|
||||||
subdirs=['include', 'src/libFLAC'],
|
subdirs=['include', 'src/libFLAC'],
|
||||||
)
|
)
|
||||||
|
|
||||||
zlib = ZlibProject(
|
zlib = ZlibProject(
|
||||||
'http://zlib.net/zlib-1.2.12.tar.xz',
|
('http://zlib.net/zlib-1.3.1.tar.xz',
|
||||||
'7db46b8d7726232a621befaab4a1c870f00a90805511c0e0090441dac57def18',
|
'https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.xz'),
|
||||||
|
'38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32',
|
||||||
'lib/libz.a',
|
'lib/libz.a',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -109,33 +112,35 @@ libmodplug = AutotoolsProject(
|
|||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
],
|
],
|
||||||
|
patches='src/lib/modplug/patches',
|
||||||
)
|
)
|
||||||
|
|
||||||
libopenmpt = AutotoolsProject(
|
libopenmpt = AutotoolsProject(
|
||||||
'https://lib.openmpt.org/files/libopenmpt/src/libopenmpt-0.5.12+release.autotools.tar.gz',
|
'https://lib.openmpt.org/files/libopenmpt/src/libopenmpt-0.7.9+release.autotools.tar.gz',
|
||||||
'892aea7a599b5d21842bebf463b5aafdad5711be7008dd84401920c6234820af',
|
'0386e918d75d797e79d5b14edd0847165d8b359e9811ef57652c0a356a2dfcf4',
|
||||||
'lib/libopenmpt.a',
|
'lib/libopenmpt.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
'--disable-openmpt123',
|
'--disable-openmpt123',
|
||||||
|
'--disable-examples',
|
||||||
|
'--disable-tests',
|
||||||
|
'--disable-doxygen-doc',
|
||||||
'--without-mpg123', '--without-ogg', '--without-vorbis', '--without-vorbisfile',
|
'--without-mpg123', '--without-ogg', '--without-vorbis', '--without-vorbisfile',
|
||||||
'--without-portaudio', '--without-portaudiocpp', '--without-sndfile',
|
'--without-portaudio', '--without-portaudiocpp', '--without-sndfile',
|
||||||
|
'--without-flac',
|
||||||
],
|
],
|
||||||
base='libopenmpt-0.5.12+release.autotools',
|
base='libopenmpt-0.7.9+release.autotools',
|
||||||
)
|
)
|
||||||
|
|
||||||
wildmidi = CmakeProject(
|
wildmidi = CmakeProject(
|
||||||
'https://codeload.github.com/Mindwerks/wildmidi/tar.gz/wildmidi-0.4.4',
|
'https://github.com/Mindwerks/wildmidi/releases/download/wildmidi-0.4.6/wildmidi-0.4.6.tar.gz',
|
||||||
'6f267c8d331e9859906837e2c197093fddec31829d2ebf7b958cf6b7ae935430',
|
'24ca992639ce76efa3737029fceb3672385d56e2ac0a15d50b40cc12d26e60de',
|
||||||
'lib/libWildMidi.a',
|
'lib/libWildMidi.a',
|
||||||
[
|
[
|
||||||
'-DBUILD_SHARED_LIBS=OFF',
|
'-DBUILD_SHARED_LIBS=OFF',
|
||||||
'-DWANT_PLAYER=OFF',
|
'-DWANT_PLAYER=OFF',
|
||||||
'-DWANT_STATIC=ON',
|
'-DWANT_STATIC=ON',
|
||||||
],
|
],
|
||||||
base='wildmidi-wildmidi-0.4.4',
|
|
||||||
name='wildmidi',
|
|
||||||
version='0.4.4',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
gme = CmakeProject(
|
gme = CmakeProject(
|
||||||
@@ -146,13 +151,13 @@ gme = CmakeProject(
|
|||||||
'-DBUILD_SHARED_LIBS=OFF',
|
'-DBUILD_SHARED_LIBS=OFF',
|
||||||
'-DENABLE_UBSAN=OFF',
|
'-DENABLE_UBSAN=OFF',
|
||||||
'-DZLIB_INCLUDE_DIR=OFF',
|
'-DZLIB_INCLUDE_DIR=OFF',
|
||||||
'-DSDL2_DIR=OFF',
|
'-DCMAKE_DISABLE_FIND_PACKAGE_SDL2=ON',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
ffmpeg = FfmpegProject(
|
ffmpeg = FfmpegProject(
|
||||||
'http://ffmpeg.org/releases/ffmpeg-5.1.tar.xz',
|
'http://ffmpeg.org/releases/ffmpeg-6.1.tar.xz',
|
||||||
'55eb6aab5ee235550fa54a33eaf8bf1b4ec66c01453182b12f6a993d75698b03',
|
'488c76e57dd9b3bee901f71d5c95eaf1db4a5a31fe46a28654e837144207c270',
|
||||||
'lib/libavcodec.a',
|
'lib/libavcodec.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -170,13 +175,16 @@ ffmpeg = FfmpegProject(
|
|||||||
'--disable-pixelutils',
|
'--disable-pixelutils',
|
||||||
'--disable-network',
|
'--disable-network',
|
||||||
'--disable-encoders',
|
'--disable-encoders',
|
||||||
|
'--disable-hwaccels',
|
||||||
'--disable-muxers',
|
'--disable-muxers',
|
||||||
'--disable-protocols',
|
'--disable-protocols',
|
||||||
'--disable-devices',
|
'--disable-devices',
|
||||||
'--disable-filters',
|
'--disable-filters',
|
||||||
'--disable-v4l2_m2m',
|
'--disable-v4l2_m2m',
|
||||||
|
|
||||||
|
'--disable-sdl2',
|
||||||
'--disable-vulkan',
|
'--disable-vulkan',
|
||||||
|
'--disable-xlib',
|
||||||
|
|
||||||
'--disable-parser=bmp',
|
'--disable-parser=bmp',
|
||||||
'--disable-parser=cavsvideo',
|
'--disable-parser=cavsvideo',
|
||||||
@@ -190,17 +198,22 @@ ffmpeg = FfmpegProject(
|
|||||||
'--disable-parser=h263',
|
'--disable-parser=h263',
|
||||||
'--disable-parser=h264',
|
'--disable-parser=h264',
|
||||||
'--disable-parser=hevc',
|
'--disable-parser=hevc',
|
||||||
|
'--disable-parser=jpeg2000',
|
||||||
'--disable-parser=mjpeg',
|
'--disable-parser=mjpeg',
|
||||||
'--disable-parser=mlp',
|
'--disable-parser=mlp',
|
||||||
'--disable-parser=mpeg4video',
|
'--disable-parser=mpeg4video',
|
||||||
'--disable-parser=mpegvideo',
|
'--disable-parser=mpegvideo',
|
||||||
'--disable-parser=opus',
|
'--disable-parser=opus',
|
||||||
|
'--disable-parser=qoi',
|
||||||
|
'--disable-parser=rv30',
|
||||||
|
'--disable-parser=rv40',
|
||||||
'--disable-parser=vc1',
|
'--disable-parser=vc1',
|
||||||
'--disable-parser=vp3',
|
'--disable-parser=vp3',
|
||||||
'--disable-parser=vp8',
|
'--disable-parser=vp8',
|
||||||
'--disable-parser=vp9',
|
'--disable-parser=vp9',
|
||||||
'--disable-parser=png',
|
'--disable-parser=png',
|
||||||
'--disable-parser=pnm',
|
'--disable-parser=pnm',
|
||||||
|
'--disable-parser=webp',
|
||||||
'--disable-parser=xma',
|
'--disable-parser=xma',
|
||||||
|
|
||||||
'--disable-demuxer=aqtitle',
|
'--disable-demuxer=aqtitle',
|
||||||
@@ -216,6 +229,42 @@ ffmpeg = FfmpegProject(
|
|||||||
'--disable-demuxer=h264',
|
'--disable-demuxer=h264',
|
||||||
'--disable-demuxer=ico',
|
'--disable-demuxer=ico',
|
||||||
'--disable-demuxer=image2',
|
'--disable-demuxer=image2',
|
||||||
|
'--disable-demuxer=image2pipe',
|
||||||
|
'--disable-demuxer=image_bmp_pipe',
|
||||||
|
'--disable-demuxer=image_cri_pipe',
|
||||||
|
'--disable-demuxer=image_dds_pipe',
|
||||||
|
'--disable-demuxer=image_dpx_pipe',
|
||||||
|
'--disable-demuxer=image_exr_pipe',
|
||||||
|
'--disable-demuxer=image_gem_pipe',
|
||||||
|
'--disable-demuxer=image_gif_pipe',
|
||||||
|
'--disable-demuxer=image_j2k_pipe',
|
||||||
|
'--disable-demuxer=image_jpeg_pipe',
|
||||||
|
'--disable-demuxer=image_jpegls_pipe',
|
||||||
|
'--disable-demuxer=image_jpegxl_pipe',
|
||||||
|
'--disable-demuxer=image_pam_pipe',
|
||||||
|
'--disable-demuxer=image_pbm_pipe',
|
||||||
|
'--disable-demuxer=image_pcx_pipe',
|
||||||
|
'--disable-demuxer=image_pfm_pipe',
|
||||||
|
'--disable-demuxer=image_pgm_pipe',
|
||||||
|
'--disable-demuxer=image_pgmyuv_pipe',
|
||||||
|
'--disable-demuxer=image_pgx_pipe',
|
||||||
|
'--disable-demuxer=image_phm_pipe',
|
||||||
|
'--disable-demuxer=image_photocd_pipe',
|
||||||
|
'--disable-demuxer=image_pictor_pipe',
|
||||||
|
'--disable-demuxer=image_png_pipe',
|
||||||
|
'--disable-demuxer=image_ppm_pipe',
|
||||||
|
'--disable-demuxer=image_psd_pipe',
|
||||||
|
'--disable-demuxer=image_qdraw_pipe',
|
||||||
|
'--disable-demuxer=image_qoi_pipe',
|
||||||
|
'--disable-demuxer=image_sgi_pipe',
|
||||||
|
'--disable-demuxer=image_sunrast_pipe',
|
||||||
|
'--disable-demuxer=image_svg_pipe',
|
||||||
|
'--disable-demuxer=image_tiff_pipe',
|
||||||
|
'--disable-demuxer=image_vbn_pipe',
|
||||||
|
'--disable-demuxer=image_webp_pipe',
|
||||||
|
'--disable-demuxer=image_xbm_pipe',
|
||||||
|
'--disable-demuxer=image_xpm_pipe',
|
||||||
|
'--disable-demuxer=image_xwd_pipe',
|
||||||
'--disable-demuxer=jacosub',
|
'--disable-demuxer=jacosub',
|
||||||
'--disable-demuxer=lrc',
|
'--disable-demuxer=lrc',
|
||||||
'--disable-demuxer=microdvd',
|
'--disable-demuxer=microdvd',
|
||||||
@@ -238,6 +287,7 @@ ffmpeg = FfmpegProject(
|
|||||||
'--disable-demuxer=tedcaptions',
|
'--disable-demuxer=tedcaptions',
|
||||||
'--disable-demuxer=vobsub',
|
'--disable-demuxer=vobsub',
|
||||||
'--disable-demuxer=vplayer',
|
'--disable-demuxer=vplayer',
|
||||||
|
'--disable-demuxer=webm_dash_manifest',
|
||||||
'--disable-demuxer=webvtt',
|
'--disable-demuxer=webvtt',
|
||||||
'--disable-demuxer=yuv4mpegpipe',
|
'--disable-demuxer=yuv4mpegpipe',
|
||||||
|
|
||||||
@@ -267,78 +317,181 @@ ffmpeg = FfmpegProject(
|
|||||||
'--disable-decoder=qdmc',
|
'--disable-decoder=qdmc',
|
||||||
|
|
||||||
# disable lots of image and video codecs
|
# disable lots of image and video codecs
|
||||||
|
'--disable-decoder=acelp_kelvin',
|
||||||
|
'--disable-decoder=agm',
|
||||||
|
'--disable-decoder=aic',
|
||||||
|
'--disable-decoder=alias_pix',
|
||||||
|
'--disable-decoder=ansi',
|
||||||
|
'--disable-decoder=apng',
|
||||||
|
'--disable-decoder=arbc',
|
||||||
|
'--disable-decoder=argo',
|
||||||
'--disable-decoder=ass',
|
'--disable-decoder=ass',
|
||||||
'--disable-decoder=asv1',
|
'--disable-decoder=asv1',
|
||||||
'--disable-decoder=asv2',
|
'--disable-decoder=asv2',
|
||||||
'--disable-decoder=apng',
|
'--disable-decoder=aura',
|
||||||
|
'--disable-decoder=aura2',
|
||||||
'--disable-decoder=avrn',
|
'--disable-decoder=avrn',
|
||||||
'--disable-decoder=avrp',
|
'--disable-decoder=avrp',
|
||||||
|
'--disable-decoder=avui',
|
||||||
|
'--disable-decoder=ayuv',
|
||||||
'--disable-decoder=bethsoftvid',
|
'--disable-decoder=bethsoftvid',
|
||||||
|
'--disable-decoder=bfi',
|
||||||
'--disable-decoder=bink',
|
'--disable-decoder=bink',
|
||||||
|
'--disable-decoder=bintext',
|
||||||
|
'--disable-decoder=bitpacked',
|
||||||
'--disable-decoder=bmp',
|
'--disable-decoder=bmp',
|
||||||
'--disable-decoder=bmv_video',
|
'--disable-decoder=bmv_video',
|
||||||
|
'--disable-decoder=brender_pix',
|
||||||
|
'--disable-decoder=c93',
|
||||||
'--disable-decoder=cavs',
|
'--disable-decoder=cavs',
|
||||||
'--disable-decoder=ccaption',
|
'--disable-decoder=ccaption',
|
||||||
'--disable-decoder=cdgraphics',
|
'--disable-decoder=cdgraphics',
|
||||||
|
'--disable-decoder=cdtoons',
|
||||||
|
'--disable-decoder=cdxl',
|
||||||
|
'--disable-decoder=cfhd',
|
||||||
|
'--disable-decoder=cinepak',
|
||||||
'--disable-decoder=clearvideo',
|
'--disable-decoder=clearvideo',
|
||||||
|
'--disable-decoder=cljr',
|
||||||
|
'--disable-decoder=cllc',
|
||||||
|
'--disable-decoder=cpia',
|
||||||
|
'--disable-decoder=cscd',
|
||||||
|
'--disable-decoder=cyuv',
|
||||||
|
'--disable-decoder=dds',
|
||||||
'--disable-decoder=dirac',
|
'--disable-decoder=dirac',
|
||||||
|
'--disable-decoder=dnxhd',
|
||||||
|
'--disable-decoder=dpx',
|
||||||
'--disable-decoder=dsicinvideo',
|
'--disable-decoder=dsicinvideo',
|
||||||
'--disable-decoder=dvbsub',
|
'--disable-decoder=dvbsub',
|
||||||
'--disable-decoder=dvdsub',
|
'--disable-decoder=dvdsub',
|
||||||
'--disable-decoder=dvvideo',
|
'--disable-decoder=dvvideo',
|
||||||
|
'--disable-decoder=dxa',
|
||||||
|
'--disable-decoder=dxtory',
|
||||||
|
'--disable-decoder=dxv',
|
||||||
|
'--disable-decoder=eacmv',
|
||||||
|
'--disable-decoder=eamad',
|
||||||
|
'--disable-decoder=eatgq',
|
||||||
|
'--disable-decoder=eatgv',
|
||||||
|
'--disable-decoder=eatqi',
|
||||||
|
'--disable-decoder=eightbps',
|
||||||
|
'--disable-decoder=escape124',
|
||||||
|
'--disable-decoder=escape130',
|
||||||
'--disable-decoder=exr',
|
'--disable-decoder=exr',
|
||||||
'--disable-decoder=ffv1',
|
'--disable-decoder=ffv1',
|
||||||
'--disable-decoder=ffvhuff',
|
'--disable-decoder=ffvhuff',
|
||||||
'--disable-decoder=ffwavesynth',
|
'--disable-decoder=ffwavesynth',
|
||||||
|
'--disable-decoder=fic',
|
||||||
|
'--disable-decoder=fits',
|
||||||
|
'--disable-decoder=flashsv',
|
||||||
|
'--disable-decoder=flashsv2',
|
||||||
'--disable-decoder=flic',
|
'--disable-decoder=flic',
|
||||||
'--disable-decoder=flv',
|
'--disable-decoder=flv',
|
||||||
|
'--disable-decoder=fmvc',
|
||||||
'--disable-decoder=fraps',
|
'--disable-decoder=fraps',
|
||||||
|
'--disable-decoder=fourxm',
|
||||||
|
'--disable-decoder=frwu',
|
||||||
|
'--disable-decoder=g2m',
|
||||||
|
'--disable-decoder=gdv',
|
||||||
|
'--disable-decoder=gem',
|
||||||
'--disable-decoder=gif',
|
'--disable-decoder=gif',
|
||||||
'--disable-decoder=h261',
|
'--disable-decoder=h261',
|
||||||
'--disable-decoder=h263',
|
'--disable-decoder=h263',
|
||||||
'--disable-decoder=h263i',
|
'--disable-decoder=h263i',
|
||||||
'--disable-decoder=h263p',
|
'--disable-decoder=h263p',
|
||||||
'--disable-decoder=h264',
|
'--disable-decoder=h264',
|
||||||
|
'--disable-decoder=hap',
|
||||||
'--disable-decoder=hevc',
|
'--disable-decoder=hevc',
|
||||||
'--disable-decoder=hnm4_video',
|
'--disable-decoder=hnm4_video',
|
||||||
'--disable-decoder=hq_hqa',
|
'--disable-decoder=hq_hqa',
|
||||||
'--disable-decoder=hqx',
|
'--disable-decoder=hqx',
|
||||||
|
'--disable-decoder=huffyuv',
|
||||||
|
'--disable-decoder=hymt',
|
||||||
'--disable-decoder=idcin',
|
'--disable-decoder=idcin',
|
||||||
|
'--disable-decoder=idf',
|
||||||
'--disable-decoder=iff_ilbm',
|
'--disable-decoder=iff_ilbm',
|
||||||
|
'--disable-decoder=imm4',
|
||||||
'--disable-decoder=indeo2',
|
'--disable-decoder=indeo2',
|
||||||
'--disable-decoder=indeo3',
|
'--disable-decoder=indeo3',
|
||||||
'--disable-decoder=indeo4',
|
'--disable-decoder=indeo4',
|
||||||
'--disable-decoder=indeo5',
|
'--disable-decoder=indeo5',
|
||||||
'--disable-decoder=interplay_video',
|
'--disable-decoder=interplay_video',
|
||||||
|
'--disable-decoder=ipu',
|
||||||
'--disable-decoder=jacosub',
|
'--disable-decoder=jacosub',
|
||||||
'--disable-decoder=jpeg2000',
|
'--disable-decoder=jpeg2000',
|
||||||
'--disable-decoder=jpegls',
|
'--disable-decoder=jpegls',
|
||||||
|
'--disable-decoder=jv',
|
||||||
|
'--disable-decoder=kgv1',
|
||||||
|
'--disable-decoder=kmvc',
|
||||||
|
'--disable-decoder=lagarith',
|
||||||
|
'--disable-decoder=loco',
|
||||||
|
'--disable-decoder=lscr',
|
||||||
|
'--disable-decoder=m101',
|
||||||
|
'--disable-decoder=magicyuv',
|
||||||
|
'--disable-decoder=mdec',
|
||||||
'--disable-decoder=microdvd',
|
'--disable-decoder=microdvd',
|
||||||
'--disable-decoder=mimic',
|
'--disable-decoder=mimic',
|
||||||
'--disable-decoder=mjpeg',
|
'--disable-decoder=mjpeg',
|
||||||
'--disable-decoder=mmvideo',
|
'--disable-decoder=mmvideo',
|
||||||
'--disable-decoder=mpl2',
|
'--disable-decoder=mpl2',
|
||||||
|
'--disable-decoder=mobiclip',
|
||||||
'--disable-decoder=motionpixels',
|
'--disable-decoder=motionpixels',
|
||||||
|
'--disable-decoder=movtext',
|
||||||
'--disable-decoder=mpeg1video',
|
'--disable-decoder=mpeg1video',
|
||||||
'--disable-decoder=mpeg2video',
|
'--disable-decoder=mpeg2video',
|
||||||
'--disable-decoder=mpeg4',
|
'--disable-decoder=mpeg4',
|
||||||
'--disable-decoder=mpegvideo',
|
'--disable-decoder=mpegvideo',
|
||||||
|
'--disable-decoder=msa1',
|
||||||
'--disable-decoder=mscc',
|
'--disable-decoder=mscc',
|
||||||
'--disable-decoder=msmpeg4_crystalhd',
|
'--disable-decoder=msmpeg4_crystalhd',
|
||||||
'--disable-decoder=msmpeg4v1',
|
'--disable-decoder=msmpeg4v1',
|
||||||
'--disable-decoder=msmpeg4v2',
|
'--disable-decoder=msmpeg4v2',
|
||||||
'--disable-decoder=msmpeg4v3',
|
'--disable-decoder=msmpeg4v3',
|
||||||
|
'--disable-decoder=msp2',
|
||||||
|
'--disable-decoder=msrle',
|
||||||
|
'--disable-decoder=mss1',
|
||||||
'--disable-decoder=msvideo1',
|
'--disable-decoder=msvideo1',
|
||||||
'--disable-decoder=mszh',
|
'--disable-decoder=mszh',
|
||||||
|
'--disable-decoder=mts2',
|
||||||
|
'--disable-decoder=mv30',
|
||||||
'--disable-decoder=mvc1',
|
'--disable-decoder=mvc1',
|
||||||
'--disable-decoder=mvc2',
|
'--disable-decoder=mvc2',
|
||||||
|
'--disable-decoder=mvdv',
|
||||||
|
'--disable-decoder=mvha',
|
||||||
|
'--disable-decoder=mwsc',
|
||||||
|
'--disable-decoder=notchlc',
|
||||||
|
'--disable-decoder=nuv',
|
||||||
'--disable-decoder=on2avc',
|
'--disable-decoder=on2avc',
|
||||||
'--disable-decoder=paf_video',
|
'--disable-decoder=paf_video',
|
||||||
|
'--disable-decoder=pam',
|
||||||
|
'--disable-decoder=pbm',
|
||||||
|
'--disable-decoder=pcx',
|
||||||
|
'--disable-decoder=pdv',
|
||||||
|
'--disable-decoder=pfm',
|
||||||
|
'--disable-decoder=pgm',
|
||||||
|
'--disable-decoder=pgmyuv',
|
||||||
|
'--disable-decoder=pgssub',
|
||||||
|
'--disable-decoder=pgx',
|
||||||
|
'--disable-decoder=phm',
|
||||||
|
'--disable-decoder=photocd',
|
||||||
'--disable-decoder=png',
|
'--disable-decoder=png',
|
||||||
|
'--disable-decoder=pictor',
|
||||||
|
'--disable-decoder=pixlet',
|
||||||
|
'--disable-decoder=pjs',
|
||||||
|
'--disable-decoder=ppm',
|
||||||
|
'--disable-decoder=prores',
|
||||||
|
'--disable-decoder=prosumer',
|
||||||
|
'--disable-decoder=psd',
|
||||||
|
'--disable-decoder=ptx',
|
||||||
'--disable-decoder=qdraw',
|
'--disable-decoder=qdraw',
|
||||||
|
'--disable-decoder=qoi',
|
||||||
'--disable-decoder=qpeg',
|
'--disable-decoder=qpeg',
|
||||||
|
'--disable-decoder=qtrle',
|
||||||
'--disable-decoder=rawvideo',
|
'--disable-decoder=rawvideo',
|
||||||
|
'--disable-decoder=r10k',
|
||||||
|
'--disable-decoder=r210',
|
||||||
|
'--disable-decoder=rasc',
|
||||||
'--disable-decoder=realtext',
|
'--disable-decoder=realtext',
|
||||||
|
'--disable-decoder=rl2',
|
||||||
|
'--disable-decoder=rpza',
|
||||||
'--disable-decoder=roq',
|
'--disable-decoder=roq',
|
||||||
'--disable-decoder=roq_dpcm',
|
'--disable-decoder=roq_dpcm',
|
||||||
'--disable-decoder=rscc',
|
'--disable-decoder=rscc',
|
||||||
@@ -347,53 +500,122 @@ ffmpeg = FfmpegProject(
|
|||||||
'--disable-decoder=rv30',
|
'--disable-decoder=rv30',
|
||||||
'--disable-decoder=rv40',
|
'--disable-decoder=rv40',
|
||||||
'--disable-decoder=sami',
|
'--disable-decoder=sami',
|
||||||
|
'--disable-decoder=sanm',
|
||||||
|
'--disable-decoder=scpr',
|
||||||
|
'--disable-decoder=screenpresso',
|
||||||
|
'--disable-decoder=sga',
|
||||||
|
'--disable-decoder=sgi',
|
||||||
|
'--disable-decoder=sgirle',
|
||||||
'--disable-decoder=sheervideo',
|
'--disable-decoder=sheervideo',
|
||||||
|
'--disable-decoder=simbiosis_imx',
|
||||||
|
'--disable-decoder=smc',
|
||||||
'--disable-decoder=snow',
|
'--disable-decoder=snow',
|
||||||
|
'--disable-decoder=speedhq',
|
||||||
|
'--disable-decoder=srgc',
|
||||||
'--disable-decoder=srt',
|
'--disable-decoder=srt',
|
||||||
|
'--disable-decoder=ssa',
|
||||||
'--disable-decoder=stl',
|
'--disable-decoder=stl',
|
||||||
'--disable-decoder=subrip',
|
'--disable-decoder=subrip',
|
||||||
'--disable-decoder=subviewer',
|
'--disable-decoder=subviewer',
|
||||||
'--disable-decoder=subviewer1',
|
'--disable-decoder=subviewer1',
|
||||||
|
'--disable-decoder=sunrast',
|
||||||
'--disable-decoder=svq1',
|
'--disable-decoder=svq1',
|
||||||
'--disable-decoder=svq3',
|
'--disable-decoder=svq3',
|
||||||
|
'--disable-decoder=targa',
|
||||||
|
'--disable-decoder=targa_y216',
|
||||||
|
'--disable-decoder=text',
|
||||||
'--disable-decoder=tiff',
|
'--disable-decoder=tiff',
|
||||||
'--disable-decoder=tiertexseqvideo',
|
'--disable-decoder=tiertexseqvideo',
|
||||||
|
'--disable-decoder=tmv',
|
||||||
'--disable-decoder=truemotion1',
|
'--disable-decoder=truemotion1',
|
||||||
'--disable-decoder=truemotion2',
|
'--disable-decoder=truemotion2',
|
||||||
'--disable-decoder=truemotion2rt',
|
'--disable-decoder=truemotion2rt',
|
||||||
|
'--disable-decoder=tscc',
|
||||||
|
'--disable-decoder=tscc2',
|
||||||
'--disable-decoder=twinvq',
|
'--disable-decoder=twinvq',
|
||||||
|
'--disable-decoder=txd',
|
||||||
|
'--disable-decoder=ulti',
|
||||||
'--disable-decoder=utvideo',
|
'--disable-decoder=utvideo',
|
||||||
|
'--disable-decoder=v210',
|
||||||
|
'--disable-decoder=v210x',
|
||||||
|
'--disable-decoder=v308',
|
||||||
|
'--disable-decoder=v408',
|
||||||
|
'--disable-decoder=v410',
|
||||||
|
'--disable-decoder=vb',
|
||||||
|
'--disable-decoder=vble',
|
||||||
|
'--disable-decoder=vbn',
|
||||||
'--disable-decoder=vc1',
|
'--disable-decoder=vc1',
|
||||||
|
'--disable-decoder=vcr1',
|
||||||
'--disable-decoder=vmdvideo',
|
'--disable-decoder=vmdvideo',
|
||||||
|
'--disable-decoder=vmnc',
|
||||||
'--disable-decoder=vp3',
|
'--disable-decoder=vp3',
|
||||||
'--disable-decoder=vp5',
|
'--disable-decoder=vp5',
|
||||||
'--disable-decoder=vp6',
|
'--disable-decoder=vp6',
|
||||||
'--disable-decoder=vp7',
|
'--disable-decoder=vp7',
|
||||||
'--disable-decoder=vp8',
|
'--disable-decoder=vp8',
|
||||||
'--disable-decoder=vp9',
|
'--disable-decoder=vp9',
|
||||||
|
'--disable-decoder=vplayer',
|
||||||
'--disable-decoder=vqa',
|
'--disable-decoder=vqa',
|
||||||
'--disable-decoder=webvtt',
|
'--disable-decoder=webvtt',
|
||||||
|
'--disable-decoder=wcmv',
|
||||||
'--disable-decoder=wmv1',
|
'--disable-decoder=wmv1',
|
||||||
'--disable-decoder=wmv2',
|
'--disable-decoder=wmv2',
|
||||||
'--disable-decoder=wmv3',
|
'--disable-decoder=wmv3',
|
||||||
|
'--disable-decoder=wnv1',
|
||||||
|
'--disable-decoder=wrapped_avframe',
|
||||||
|
'--disable-decoder=xan_wc3',
|
||||||
|
'--disable-decoder=xan_wc4',
|
||||||
|
'--disable-decoder=xbin',
|
||||||
|
'--disable-decoder=xbm',
|
||||||
|
'--disable-decoder=xface',
|
||||||
|
'--disable-decoder=xl',
|
||||||
|
'--disable-decoder=xpm',
|
||||||
|
'--disable-decoder=xsub',
|
||||||
|
'--disable-decoder=xwd',
|
||||||
|
'--disable-decoder=y41p',
|
||||||
|
'--disable-decoder=ylc',
|
||||||
|
'--disable-decoder=yop',
|
||||||
'--disable-decoder=yuv4',
|
'--disable-decoder=yuv4',
|
||||||
|
'--disable-decoder=zero12v',
|
||||||
|
'--disable-decoder=zerocodec',
|
||||||
|
'--disable-decoder=zlib',
|
||||||
|
'--disable-decoder=zmbv',
|
||||||
|
|
||||||
|
'--disable-bsf=av1_frame_merge',
|
||||||
|
'--disable-bsf=av1_frame_split',
|
||||||
|
'--disable-bsf=av1_metadata',
|
||||||
|
'--disable-bsf=dts2pts',
|
||||||
|
'--disable-bsf=h264_metadata',
|
||||||
|
'--disable-bsf=h264_mp4toannexb',
|
||||||
|
'--disable-bsf=h264_redundant_pps',
|
||||||
|
'--disable-bsf=hevc_metadata',
|
||||||
|
'--disable-bsf=hevc_mp4toannexb',
|
||||||
|
'--disable-bsf=mjpeg2jpeg',
|
||||||
|
'--disable-bsf=opus_metadata',
|
||||||
|
'--disable-bsf=pgs_frame_merge',
|
||||||
|
'--disable-bsf=text2movsub',
|
||||||
|
'--disable-bsf=vp9_metadata',
|
||||||
|
'--disable-bsf=vp9_raw_reorder',
|
||||||
|
'--disable-bsf=vp9_superframe',
|
||||||
|
'--disable-bsf=vp9_superframe_split',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
openssl = OpenSSLProject(
|
openssl = OpenSSLProject(
|
||||||
'https://www.openssl.org/source/openssl-3.0.5.tar.gz',
|
('https://www.openssl.org/source/openssl-3.1.4.tar.gz',
|
||||||
'aa7d8d9bef71ad6525c55ba11e5f4397889ce49c2c9349dcea6d3e4f0b024a7a',
|
'https://artfiles.org/openssl.org/source/openssl-3.1.4.tar.gz'),
|
||||||
|
'840af5366ab9b522bde525826be3ef0fb0af81c6a9ebd84caa600fea1731eee3',
|
||||||
'include/openssl/ossl_typ.h',
|
'include/openssl/ossl_typ.h',
|
||||||
)
|
)
|
||||||
|
|
||||||
curl = CmakeProject(
|
curl = CmakeProject(
|
||||||
'https://curl.se/download/curl-7.84.0.tar.xz',
|
('https://curl.se/download/curl-8.5.0.tar.xz',
|
||||||
'2d118b43f547bfe5bae806d8d47b4e596ea5b25a6c1f080aef49fbcd817c5db8',
|
'https://github.com/curl/curl/releases/download/curl-8_5_0/curl-8.5.0.tar.xz'),
|
||||||
|
'42ab8db9e20d8290a3b633e7fbb3cec15db34df65fd1015ef8ac1e4723750eeb',
|
||||||
'lib/libcurl.a',
|
'lib/libcurl.a',
|
||||||
[
|
[
|
||||||
'-DBUILD_CURL_EXE=OFF',
|
'-DBUILD_CURL_EXE=OFF',
|
||||||
'-DBUILD_SHARED_LIBS=OFF',
|
'-DBUILD_SHARED_LIBS=OFF',
|
||||||
'-DCURL_DISABLE_VERBOSE_STRINGS=ON',
|
|
||||||
'-DCURL_DISABLE_LDAP=ON',
|
'-DCURL_DISABLE_LDAP=ON',
|
||||||
'-DCURL_DISABLE_TELNET=ON',
|
'-DCURL_DISABLE_TELNET=ON',
|
||||||
'-DCURL_DISABLE_DICT=ON',
|
'-DCURL_DISABLE_DICT=ON',
|
||||||
@@ -422,8 +644,8 @@ curl = CmakeProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
libnfs = AutotoolsProject(
|
libnfs = AutotoolsProject(
|
||||||
'https://github.com/sahlberg/libnfs/archive/libnfs-5.0.1.tar.gz',
|
'https://github.com/sahlberg/libnfs/archive/libnfs-5.0.3.tar.gz',
|
||||||
'7ef445410b42f36b9bad426608b53ccb9ccca4101e545c383f564c11db672ca8',
|
'd945cb4f4c8f82ee1f3640893a168810f794a28e1010bb007ec5add345e9df3e',
|
||||||
'lib/libnfs.a',
|
'lib/libnfs.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -434,7 +656,7 @@ libnfs = AutotoolsProject(
|
|||||||
|
|
||||||
'--disable-utils', '--disable-examples',
|
'--disable-utils', '--disable-examples',
|
||||||
],
|
],
|
||||||
base='libnfs-libnfs-5.0.1',
|
base='libnfs-libnfs-5.0.3',
|
||||||
autoreconf=True,
|
autoreconf=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -445,7 +667,7 @@ jack = JackProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
boost = BoostProject(
|
boost = BoostProject(
|
||||||
'https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2',
|
'https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.bz2',
|
||||||
'475d589d51a7f8b3ba2ba4eda022b170e562ca3b760ee922c146b6c65856ef39',
|
'71feeed900fbccca04a3b4f2f84a7c217186f28a940ed8b7ed4725986baf99fa',
|
||||||
'include/boost/version.hpp',
|
'include/boost/version.hpp',
|
||||||
)
|
)
|
||||||
|
@@ -1,28 +1,35 @@
|
|||||||
import subprocess
|
import subprocess, multiprocessing
|
||||||
|
from typing import Optional, Sequence, Union
|
||||||
|
|
||||||
from build.project import Project
|
from build.project import Project
|
||||||
|
from .toolchain import AnyToolchain
|
||||||
|
|
||||||
class MakeProject(Project):
|
class MakeProject(Project):
|
||||||
def __init__(self, url, md5, installed,
|
def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
|
||||||
install_target='install',
|
install_target: str='install',
|
||||||
**kwargs):
|
**kwargs):
|
||||||
Project.__init__(self, url, md5, installed, **kwargs)
|
Project.__init__(self, url, md5, installed, **kwargs)
|
||||||
self.install_target = install_target
|
self.install_target = install_target
|
||||||
|
|
||||||
def get_simultaneous_jobs(self):
|
def get_simultaneous_jobs(self) -> int:
|
||||||
return 12
|
try:
|
||||||
|
# use twice as many simultaneous jobs as we have CPU cores
|
||||||
|
return multiprocessing.cpu_count() * 2
|
||||||
|
except NotImplementedError:
|
||||||
|
# default to 12, if multiprocessing.cpu_count() is not implemented
|
||||||
|
return 12
|
||||||
|
|
||||||
def get_make_args(self, toolchain):
|
def get_make_args(self, toolchain: AnyToolchain) -> list[str]:
|
||||||
return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
|
return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
|
||||||
|
|
||||||
def get_make_install_args(self, toolchain):
|
def get_make_install_args(self, toolchain: AnyToolchain) -> list[str]:
|
||||||
return ['--quiet', self.install_target]
|
return ['--quiet', self.install_target]
|
||||||
|
|
||||||
def make(self, toolchain, wd, args):
|
def make(self, toolchain: AnyToolchain, wd: str, args: list[str]) -> None:
|
||||||
subprocess.check_call(['/usr/bin/make'] + args,
|
subprocess.check_call(['make'] + args,
|
||||||
cwd=wd, env=toolchain.env)
|
cwd=wd, env=toolchain.env)
|
||||||
|
|
||||||
def build_make(self, toolchain, wd, install=True):
|
def build_make(self, toolchain: AnyToolchain, wd: str, install: bool=True) -> None:
|
||||||
self.make(toolchain, wd, self.get_make_args(toolchain))
|
self.make(toolchain, wd, self.get_make_args(toolchain))
|
||||||
if install:
|
if install:
|
||||||
self.make(toolchain, wd, self.get_make_install_args(toolchain))
|
self.make(toolchain, wd, self.get_make_install_args(toolchain))
|
||||||
|
@@ -1,9 +1,17 @@
|
|||||||
import os.path, subprocess, sys
|
import os
|
||||||
|
import subprocess
|
||||||
import platform
|
import platform
|
||||||
|
from typing import Optional, Sequence, Union
|
||||||
|
|
||||||
from build.project import Project
|
from build.project import Project
|
||||||
|
from .toolchain import AnyToolchain
|
||||||
|
|
||||||
def make_cross_file(toolchain):
|
def __no_ccache(cmd: str) -> str:
|
||||||
|
if cmd.startswith('ccache '):
|
||||||
|
cmd = cmd[7:]
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
def make_cross_file(toolchain: AnyToolchain) -> str:
|
||||||
if toolchain.is_windows:
|
if toolchain.is_windows:
|
||||||
system = 'windows'
|
system = 'windows'
|
||||||
windres = "windres = '%s'" % toolchain.windres
|
windres = "windres = '%s'" % toolchain.windres
|
||||||
@@ -22,7 +30,7 @@ def make_cross_file(toolchain):
|
|||||||
cpu = 'arm64-v8a'
|
cpu = 'arm64-v8a'
|
||||||
else:
|
else:
|
||||||
cpu_family = 'x86'
|
cpu_family = 'x86'
|
||||||
if 'x86_64' in toolchain.arch:
|
if 'x86_64' in toolchain.host_triplet:
|
||||||
cpu = 'x86_64'
|
cpu = 'x86_64'
|
||||||
else:
|
else:
|
||||||
cpu = 'i686'
|
cpu = 'i686'
|
||||||
@@ -37,8 +45,8 @@ def make_cross_file(toolchain):
|
|||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
f.write(f"""
|
f.write(f"""
|
||||||
[binaries]
|
[binaries]
|
||||||
c = '{toolchain.cc}'
|
c = '{__no_ccache(toolchain.cc)}'
|
||||||
cpp = '{toolchain.cxx}'
|
cpp = '{__no_ccache(toolchain.cxx)}'
|
||||||
ar = '{toolchain.ar}'
|
ar = '{toolchain.ar}'
|
||||||
strip = '{toolchain.strip}'
|
strip = '{toolchain.strip}'
|
||||||
pkgconfig = '{toolchain.pkg_config}'
|
pkgconfig = '{toolchain.pkg_config}'
|
||||||
@@ -55,7 +63,7 @@ pkgconfig = '{toolchain.pkg_config}'
|
|||||||
root = '{toolchain.install_prefix}'
|
root = '{toolchain.install_prefix}'
|
||||||
""")
|
""")
|
||||||
|
|
||||||
if 'android' in toolchain.arch:
|
if toolchain.is_android:
|
||||||
f.write("""
|
f.write("""
|
||||||
# Keep Meson from executing Android-x86 test binariees
|
# Keep Meson from executing Android-x86 test binariees
|
||||||
needs_exe_wrapper = true
|
needs_exe_wrapper = true
|
||||||
@@ -79,21 +87,23 @@ endian = '{endian}'
|
|||||||
""")
|
""")
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def configure(toolchain, src, build, args=()):
|
def configure(toolchain: AnyToolchain, src: str, build: str, args: list[str]=[]) -> None:
|
||||||
cross_file = make_cross_file(toolchain)
|
|
||||||
configure = [
|
configure = [
|
||||||
'meson',
|
'meson', 'setup',
|
||||||
src, build,
|
build, src,
|
||||||
|
|
||||||
'--prefix', toolchain.install_prefix,
|
'--prefix', toolchain.install_prefix,
|
||||||
|
|
||||||
'--buildtype', 'plain',
|
'--buildtype', 'plain',
|
||||||
|
|
||||||
'--default-library=static',
|
'--default-library=static',
|
||||||
|
|
||||||
'--cross-file', cross_file,
|
|
||||||
] + args
|
] + args
|
||||||
|
|
||||||
|
if toolchain.host_triplet is not None:
|
||||||
|
# cross-compiling: write a cross-file
|
||||||
|
cross_file = make_cross_file(toolchain)
|
||||||
|
configure.append(f'--cross-file={cross_file}')
|
||||||
|
|
||||||
env = toolchain.env.copy()
|
env = toolchain.env.copy()
|
||||||
|
|
||||||
# Meson 0.54 requires the BOOST_ROOT environment variable
|
# Meson 0.54 requires the BOOST_ROOT environment variable
|
||||||
@@ -102,18 +112,19 @@ def configure(toolchain, src, build, args=()):
|
|||||||
subprocess.check_call(configure, env=env)
|
subprocess.check_call(configure, env=env)
|
||||||
|
|
||||||
class MesonProject(Project):
|
class MesonProject(Project):
|
||||||
def __init__(self, url, md5, installed, configure_args=[],
|
def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
|
||||||
|
configure_args: list[str]=[],
|
||||||
**kwargs):
|
**kwargs):
|
||||||
Project.__init__(self, url, md5, installed, **kwargs)
|
Project.__init__(self, url, md5, installed, **kwargs)
|
||||||
self.configure_args = configure_args
|
self.configure_args = configure_args
|
||||||
|
|
||||||
def configure(self, toolchain):
|
def configure(self, toolchain: AnyToolchain) -> str:
|
||||||
src = self.unpack(toolchain)
|
src = self.unpack(toolchain)
|
||||||
build = self.make_build_path(toolchain)
|
build = self.make_build_path(toolchain)
|
||||||
configure(toolchain, src, build, self.configure_args)
|
configure(toolchain, src, build, self.configure_args)
|
||||||
return build
|
return build
|
||||||
|
|
||||||
def _build(self, toolchain):
|
def _build(self, toolchain: AnyToolchain) -> None:
|
||||||
build = self.configure(toolchain)
|
build = self.configure(toolchain)
|
||||||
subprocess.check_call(['ninja', 'install'],
|
subprocess.check_call(['ninja', '-v', 'install'],
|
||||||
cwd=build, env=toolchain.env)
|
cwd=build, env=toolchain.env)
|
||||||
|
@@ -1,13 +1,15 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
from typing import Optional, Sequence, Union
|
||||||
|
|
||||||
from build.makeproject import MakeProject
|
from build.makeproject import MakeProject
|
||||||
|
from .toolchain import AnyToolchain
|
||||||
|
|
||||||
class OpenSSLProject(MakeProject):
|
class OpenSSLProject(MakeProject):
|
||||||
def __init__(self, url, md5, installed,
|
def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
MakeProject.__init__(self, url, md5, installed, install_target='install_dev', **kwargs)
|
MakeProject.__init__(self, url, md5, installed, install_target='install_dev', **kwargs)
|
||||||
|
|
||||||
def get_make_args(self, toolchain):
|
def get_make_args(self, toolchain: AnyToolchain) -> list[str]:
|
||||||
return MakeProject.get_make_args(self, toolchain) + [
|
return MakeProject.get_make_args(self, toolchain) + [
|
||||||
'CC=' + toolchain.cc,
|
'CC=' + toolchain.cc,
|
||||||
'CFLAGS=' + toolchain.cflags,
|
'CFLAGS=' + toolchain.cflags,
|
||||||
@@ -17,45 +19,60 @@ class OpenSSLProject(MakeProject):
|
|||||||
'build_libs',
|
'build_libs',
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_make_install_args(self, toolchain):
|
def get_make_install_args(self, toolchain: AnyToolchain) -> list[str]:
|
||||||
# OpenSSL's Makefile runs "ranlib" during installation
|
# OpenSSL's Makefile runs "ranlib" during installation
|
||||||
return MakeProject.get_make_install_args(self, toolchain) + [
|
return MakeProject.get_make_install_args(self, toolchain) + [
|
||||||
'RANLIB=' + toolchain.ranlib,
|
'RANLIB=' + toolchain.ranlib,
|
||||||
]
|
]
|
||||||
|
|
||||||
def _build(self, toolchain):
|
def _build(self, toolchain: AnyToolchain) -> None:
|
||||||
src = self.unpack(toolchain, out_of_tree=False)
|
src = self.unpack(toolchain, out_of_tree=False)
|
||||||
|
|
||||||
# OpenSSL has a weird target architecture scheme with lots of
|
# OpenSSL has a weird target architecture scheme with lots of
|
||||||
# hard-coded architectures; this table translates between our
|
# hard-coded architectures; this table translates between our
|
||||||
# "toolchain_arch" (HOST_TRIPLET) and the OpenSSL target
|
# host triplet and the OpenSSL target
|
||||||
openssl_archs = {
|
openssl_archs = {
|
||||||
# not using "android-*" because those OpenSSL targets want
|
# not using "android-*" because those OpenSSL targets want
|
||||||
# to know where the SDK is, but our own build scripts
|
# to know where the SDK is, but our own build scripts
|
||||||
# prepared everything already to look like a regular Linux
|
# prepared everything already to look like a regular Linux
|
||||||
# build
|
# build
|
||||||
'arm-linux-androideabi': 'linux-generic32',
|
'armv7a-linux-androideabi': 'linux-generic32',
|
||||||
'aarch64-linux-android': 'linux-aarch64',
|
'aarch64-linux-android': 'linux-aarch64',
|
||||||
'i686-linux-android': 'linux-x86-clang',
|
'i686-linux-android': 'linux-x86-clang',
|
||||||
'x86_64-linux-android': 'linux-x86_64-clang',
|
'x86_64-linux-android': 'linux-x86_64-clang',
|
||||||
|
|
||||||
# Kobo
|
# generic Linux
|
||||||
'arm-linux-gnueabihf': 'linux-generic32',
|
'arm-linux-gnueabihf': 'linux-generic32',
|
||||||
|
|
||||||
# Windows
|
# Windows
|
||||||
'i686-w64-mingw32': 'mingw',
|
'i686-w64-mingw32': 'mingw',
|
||||||
'x86_64-w64-mingw32': 'mingw64',
|
'x86_64-w64-mingw32': 'mingw64',
|
||||||
|
|
||||||
|
# Apple
|
||||||
|
'x86_64-apple-darwin': 'darwin64-x86_64-cc',
|
||||||
|
'aarch64-apple-darwin': 'darwin64-arm64-cc',
|
||||||
}
|
}
|
||||||
|
|
||||||
openssl_arch = openssl_archs[toolchain.arch]
|
configure = [
|
||||||
|
'./Configure',
|
||||||
|
'no-shared',
|
||||||
|
'no-module',
|
||||||
|
'no-engine',
|
||||||
|
'no-static-engine',
|
||||||
|
'no-async',
|
||||||
|
'no-tests',
|
||||||
|
'no-makedepend',
|
||||||
|
'--libdir=lib', # no "lib64" on amd64, please
|
||||||
|
'--prefix=' + toolchain.install_prefix,
|
||||||
|
]
|
||||||
|
|
||||||
subprocess.check_call(['./Configure',
|
if toolchain.is_windows:
|
||||||
'no-shared',
|
# workaround for build failures
|
||||||
'no-module', 'no-engine', 'no-static-engine',
|
configure.append('no-asm')
|
||||||
'no-async',
|
|
||||||
'no-tests',
|
if toolchain.host_triplet is not None:
|
||||||
'no-asm', # "asm" causes build failures on Windows
|
configure.append(openssl_archs[toolchain.host_triplet])
|
||||||
openssl_arch,
|
configure.append(f'--cross-compile-prefix={toolchain.host_triplet}-')
|
||||||
'--prefix=' + toolchain.install_prefix],
|
|
||||||
cwd=src, env=toolchain.env)
|
subprocess.check_call(configure, cwd=src, env=toolchain.env)
|
||||||
self.build_make(toolchain, src)
|
self.build_make(toolchain, src)
|
||||||
|
@@ -1,26 +1,30 @@
|
|||||||
import os, shutil
|
import os, shutil
|
||||||
import re
|
import re
|
||||||
|
from typing import cast, BinaryIO, Optional, Sequence, Union
|
||||||
|
|
||||||
from build.download import download_and_verify
|
from build.download import download_basename, download_and_verify
|
||||||
from build.tar import untar
|
from build.tar import untar
|
||||||
from build.quilt import push_all
|
from build.quilt import push_all
|
||||||
|
from .toolchain import AnyToolchain
|
||||||
|
|
||||||
class Project:
|
class Project:
|
||||||
def __init__(self, url, md5, installed, name=None, version=None,
|
def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
|
||||||
base=None,
|
name: Optional[str]=None, version: Optional[str]=None,
|
||||||
patches=None,
|
base: Optional[str]=None,
|
||||||
|
patches: Optional[str]=None,
|
||||||
edits=None,
|
edits=None,
|
||||||
use_cxx=False):
|
use_cxx: bool=False):
|
||||||
if base is None:
|
if base is None:
|
||||||
basename = os.path.basename(url)
|
basename = download_basename(url)
|
||||||
m = re.match(r'^(.+)\.(tar(\.(gz|bz2|xz|lzma))?|zip)$', basename)
|
m = re.match(r'^(.+)\.(tar(\.(gz|bz2|xz|lzma))?|zip)$', basename)
|
||||||
if not m: raise
|
if not m: raise RuntimeError('Could not identify tarball name: ' + basename)
|
||||||
self.base = m.group(1)
|
self.base = m.group(1)
|
||||||
else:
|
else:
|
||||||
self.base = base
|
self.base = base
|
||||||
|
|
||||||
if name is None or version is None:
|
if name is None or version is None:
|
||||||
m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?[\d.]*(?:-(?:alpha|beta)\d+)?)(\+.*)?$', self.base)
|
m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?[\d.]*(?:-(?:alpha|beta)\d+)?)(\+.*)?$', self.base)
|
||||||
|
if not m: raise RuntimeError('Could not identify tarball name: ' + self.base)
|
||||||
if name is None: name = m.group(1)
|
if name is None: name = m.group(1)
|
||||||
if version is None: version = m.group(2)
|
if version is None: version = m.group(2)
|
||||||
|
|
||||||
@@ -38,10 +42,10 @@ class Project:
|
|||||||
self.edits = edits
|
self.edits = edits
|
||||||
self.use_cxx = use_cxx
|
self.use_cxx = use_cxx
|
||||||
|
|
||||||
def download(self, toolchain):
|
def download(self, toolchain: AnyToolchain) -> str:
|
||||||
return download_and_verify(self.url, self.md5, toolchain.tarball_path)
|
return download_and_verify(self.url, self.md5, toolchain.tarball_path)
|
||||||
|
|
||||||
def is_installed(self, toolchain):
|
def is_installed(self, toolchain: AnyToolchain) -> bool:
|
||||||
tarball = self.download(toolchain)
|
tarball = self.download(toolchain)
|
||||||
installed = os.path.join(toolchain.install_prefix, self.installed)
|
installed = os.path.join(toolchain.install_prefix, self.installed)
|
||||||
tarball_mtime = os.path.getmtime(tarball)
|
tarball_mtime = os.path.getmtime(tarball)
|
||||||
@@ -50,13 +54,13 @@ class Project:
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def unpack(self, toolchain, out_of_tree=True):
|
def unpack(self, toolchain: AnyToolchain, out_of_tree: bool=True) -> str:
|
||||||
if out_of_tree:
|
if out_of_tree:
|
||||||
parent_path = toolchain.src_path
|
parent_path = toolchain.src_path
|
||||||
else:
|
else:
|
||||||
parent_path = toolchain.build_path
|
parent_path = toolchain.build_path
|
||||||
path = untar(self.download(toolchain), parent_path, self.base)
|
path = untar(self.download(toolchain), parent_path, self.base,
|
||||||
|
lazy=out_of_tree and self.patches is None)
|
||||||
if self.patches is not None:
|
if self.patches is not None:
|
||||||
push_all(toolchain, path, self.patches)
|
push_all(toolchain, path, self.patches)
|
||||||
|
|
||||||
@@ -71,8 +75,10 @@ class Project:
|
|||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def make_build_path(self, toolchain):
|
def make_build_path(self, toolchain: AnyToolchain, lazy: bool=False) -> str:
|
||||||
path = os.path.join(toolchain.build_path, self.base)
|
path = os.path.join(toolchain.build_path, self.base)
|
||||||
|
if lazy and os.path.isdir(path):
|
||||||
|
return path
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
@@ -80,5 +86,5 @@ class Project:
|
|||||||
os.makedirs(path, exist_ok=True)
|
os.makedirs(path, exist_ok=True)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def build(self, toolchain):
|
def build(self, toolchain: AnyToolchain) -> None:
|
||||||
self._build(toolchain)
|
self._build(toolchain)
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
def run_quilt(toolchain, cwd, patches_path, *args):
|
from .toolchain import AnyToolchain
|
||||||
|
|
||||||
|
def run_quilt(toolchain: AnyToolchain, cwd: str, patches_path: str, *args: str) -> None:
|
||||||
env = dict(toolchain.env)
|
env = dict(toolchain.env)
|
||||||
env['QUILT_PATCHES'] = patches_path
|
env['QUILT_PATCHES'] = patches_path
|
||||||
subprocess.check_call(['quilt'] + list(args), cwd=cwd, env=env)
|
subprocess.check_call(['quilt'] + list(args), cwd=cwd, env=env)
|
||||||
|
|
||||||
def push_all(toolchain, src_path, patches_path):
|
def push_all(toolchain: AnyToolchain, src_path: str, patches_path: str) -> None:
|
||||||
run_quilt(toolchain, src_path, patches_path, 'push', '-a')
|
run_quilt(toolchain, src_path, patches_path, 'push', '-a')
|
||||||
|
@@ -1,14 +1,17 @@
|
|||||||
import os, shutil, subprocess
|
import os, shutil, subprocess
|
||||||
|
|
||||||
def untar(tarball_path, parent_path, base):
|
def untar(tarball_path: str, parent_path: str, base: str,
|
||||||
|
lazy: bool=False) -> str:
|
||||||
path = os.path.join(parent_path, base)
|
path = os.path.join(parent_path, base)
|
||||||
|
if lazy and os.path.isdir(path):
|
||||||
|
return path
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
os.makedirs(parent_path, exist_ok=True)
|
os.makedirs(parent_path, exist_ok=True)
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(['/bin/tar', 'xfC', tarball_path, parent_path])
|
subprocess.check_call(['tar', 'xfC', tarball_path, parent_path])
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
import tarfile
|
import tarfile
|
||||||
tar = tarfile.open(tarball_path)
|
tar = tarfile.open(tarball_path)
|
||||||
|
175
python/build/toolchain.py
Normal file
175
python/build/toolchain.py
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import os.path
|
||||||
|
import shutil
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
android_abis = {
|
||||||
|
'armeabi-v7a': {
|
||||||
|
'arch': 'armv7a-linux-androideabi',
|
||||||
|
'ndk_arch': 'arm',
|
||||||
|
'cflags': '-fpic -mfpu=neon -mfloat-abi=softfp',
|
||||||
|
},
|
||||||
|
|
||||||
|
'arm64-v8a': {
|
||||||
|
'arch': 'aarch64-linux-android',
|
||||||
|
'ndk_arch': 'arm64',
|
||||||
|
'cflags': '-fpic',
|
||||||
|
},
|
||||||
|
|
||||||
|
'x86': {
|
||||||
|
'arch': 'i686-linux-android',
|
||||||
|
'ndk_arch': 'x86',
|
||||||
|
'cflags': '-fPIC -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
|
||||||
|
},
|
||||||
|
|
||||||
|
'x86_64': {
|
||||||
|
'arch': 'x86_64-linux-android',
|
||||||
|
'ndk_arch': 'x86_64',
|
||||||
|
'cflags': '-fPIC -m64',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
class AndroidNdkToolchain:
|
||||||
|
def __init__(self, top_path: str, lib_path: str,
|
||||||
|
tarball_path: str, src_path: str,
|
||||||
|
ndk_path: str, android_abi: str,
|
||||||
|
use_cxx):
|
||||||
|
# build host configuration
|
||||||
|
build_arch = 'linux-x86_64'
|
||||||
|
|
||||||
|
# select the NDK target
|
||||||
|
abi_info = android_abis[android_abi]
|
||||||
|
host_triplet = abi_info['arch']
|
||||||
|
|
||||||
|
arch_path = os.path.join(lib_path, host_triplet)
|
||||||
|
|
||||||
|
self.tarball_path = tarball_path
|
||||||
|
self.src_path = src_path
|
||||||
|
self.build_path = os.path.join(arch_path, 'build')
|
||||||
|
|
||||||
|
ndk_arch = abi_info['ndk_arch']
|
||||||
|
android_api_level = '24'
|
||||||
|
|
||||||
|
install_prefix = os.path.join(arch_path, 'root')
|
||||||
|
|
||||||
|
self.host_triplet = host_triplet
|
||||||
|
self.install_prefix = install_prefix
|
||||||
|
|
||||||
|
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
|
||||||
|
llvm_triple = host_triplet + android_api_level
|
||||||
|
|
||||||
|
common_flags = '-Os -g'
|
||||||
|
common_flags += ' ' + abi_info['cflags']
|
||||||
|
|
||||||
|
llvm_bin = os.path.join(llvm_path, 'bin')
|
||||||
|
self.cc = os.path.join(llvm_bin, 'clang')
|
||||||
|
self.cxx = os.path.join(llvm_bin, 'clang++')
|
||||||
|
common_flags += ' -target ' + llvm_triple
|
||||||
|
|
||||||
|
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
|
||||||
|
|
||||||
|
self.ar = os.path.join(llvm_bin, 'llvm-ar')
|
||||||
|
self.arflags = 'rcs'
|
||||||
|
self.ranlib = os.path.join(llvm_bin, 'llvm-ranlib')
|
||||||
|
self.nm = os.path.join(llvm_bin, 'llvm-nm')
|
||||||
|
self.strip = os.path.join(llvm_bin, 'llvm-strip')
|
||||||
|
|
||||||
|
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') + \
|
||||||
|
' -Wl,--exclude-libs=ALL' + \
|
||||||
|
' ' + common_flags
|
||||||
|
self.ldflags = common_flags
|
||||||
|
self.libs = ''
|
||||||
|
|
||||||
|
self.is_arm = ndk_arch == 'arm'
|
||||||
|
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
||||||
|
self.is_aarch64 = ndk_arch == 'arm64'
|
||||||
|
self.is_windows = False
|
||||||
|
self.is_android = True
|
||||||
|
self.is_darwin = False
|
||||||
|
|
||||||
|
libstdcxx_flags = ''
|
||||||
|
libstdcxx_cxxflags = ''
|
||||||
|
libstdcxx_ldflags = ''
|
||||||
|
libstdcxx_libs = '-static-libstdc++'
|
||||||
|
|
||||||
|
if self.is_armv7:
|
||||||
|
# On 32 bit ARM, clang generates no ".eh_frame" section;
|
||||||
|
# instead, the LLVM unwinder library is used for unwinding
|
||||||
|
# the stack after a C++ exception was thrown
|
||||||
|
libstdcxx_libs += ' -lunwind'
|
||||||
|
|
||||||
|
if use_cxx:
|
||||||
|
self.cxxflags += ' ' + libstdcxx_cxxflags
|
||||||
|
self.ldflags += ' ' + libstdcxx_ldflags
|
||||||
|
self.libs += ' ' + libstdcxx_libs
|
||||||
|
|
||||||
|
self.env = dict(os.environ)
|
||||||
|
|
||||||
|
# redirect pkg-config to use our root directory instead of the
|
||||||
|
# default one on the build host
|
||||||
|
bin_dir = os.path.join(install_prefix, 'bin')
|
||||||
|
os.makedirs(bin_dir, exist_ok=True)
|
||||||
|
self.pkg_config = shutil.copy(os.path.join(top_path, 'build', 'pkg-config.sh'),
|
||||||
|
os.path.join(bin_dir, 'pkg-config'))
|
||||||
|
self.env['PKG_CONFIG'] = self.pkg_config
|
||||||
|
|
||||||
|
class MingwToolchain:
|
||||||
|
def __init__(self, top_path: str,
|
||||||
|
toolchain_path, host_triplet, x64: bool,
|
||||||
|
tarball_path, src_path, build_path, install_prefix):
|
||||||
|
self.host_triplet = host_triplet
|
||||||
|
self.tarball_path = tarball_path
|
||||||
|
self.src_path = src_path
|
||||||
|
self.build_path = build_path
|
||||||
|
self.install_prefix = install_prefix
|
||||||
|
|
||||||
|
toolchain_bin = os.path.join(toolchain_path, 'bin')
|
||||||
|
self.cc = os.path.join(toolchain_bin, host_triplet + '-gcc')
|
||||||
|
self.cxx = os.path.join(toolchain_bin, host_triplet + '-g++')
|
||||||
|
self.ar = os.path.join(toolchain_bin, host_triplet + '-ar')
|
||||||
|
self.arflags = 'rcs'
|
||||||
|
self.ranlib = os.path.join(toolchain_bin, host_triplet + '-ranlib')
|
||||||
|
self.nm = os.path.join(toolchain_bin, host_triplet + '-nm')
|
||||||
|
self.strip = os.path.join(toolchain_bin, host_triplet + '-strip')
|
||||||
|
self.windres = os.path.join(toolchain_bin, host_triplet + '-windres')
|
||||||
|
|
||||||
|
common_flags = '-O2 -g'
|
||||||
|
|
||||||
|
if not x64:
|
||||||
|
# enable SSE support which is required for LAME
|
||||||
|
common_flags += ' -march=pentium3'
|
||||||
|
|
||||||
|
self.cflags = common_flags
|
||||||
|
self.cxxflags = common_flags
|
||||||
|
self.cppflags = '-isystem ' + os.path.join(install_prefix, 'include') + \
|
||||||
|
' -DWINVER=0x0600 -D_WIN32_WINNT=0x0600'
|
||||||
|
self.ldflags = '-L' + os.path.join(install_prefix, 'lib') + \
|
||||||
|
' -static-libstdc++ -static-libgcc'
|
||||||
|
self.libs = ''
|
||||||
|
|
||||||
|
# Explicitly disable _FORTIFY_SOURCE because it is broken with
|
||||||
|
# mingw. This prevents some libraries such as libFLAC to
|
||||||
|
# enable it.
|
||||||
|
self.cppflags += ' -D_FORTIFY_SOURCE=0'
|
||||||
|
|
||||||
|
self.is_arm = host_triplet.startswith('arm')
|
||||||
|
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
||||||
|
self.is_aarch64 = host_triplet == 'aarch64'
|
||||||
|
self.is_windows = 'mingw32' in host_triplet
|
||||||
|
self.is_android = False
|
||||||
|
self.is_darwin = False
|
||||||
|
|
||||||
|
self.env = dict(os.environ)
|
||||||
|
|
||||||
|
# redirect pkg-config to use our root directory instead of the
|
||||||
|
# default one on the build host
|
||||||
|
import shutil
|
||||||
|
bin_dir = os.path.join(install_prefix, 'bin')
|
||||||
|
os.makedirs(bin_dir, exist_ok=True)
|
||||||
|
self.pkg_config = shutil.copy(os.path.join(top_path, 'build', 'pkg-config.sh'),
|
||||||
|
os.path.join(bin_dir, 'pkg-config'))
|
||||||
|
self.env['PKG_CONFIG'] = self.pkg_config
|
||||||
|
|
||||||
|
AnyToolchain = Union[AndroidNdkToolchain, MingwToolchain]
|
@@ -1,6 +1,7 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
from typing import cast, Any, BinaryIO
|
||||||
|
|
||||||
def feed_file(h, f):
|
def feed_file(h: Any, f: BinaryIO) -> None:
|
||||||
"""Feed data read from an open file into the hashlib instance."""
|
"""Feed data read from an open file into the hashlib instance."""
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -10,20 +11,20 @@ def feed_file(h, f):
|
|||||||
break
|
break
|
||||||
h.update(data)
|
h.update(data)
|
||||||
|
|
||||||
def feed_file_path(h, path):
|
def feed_file_path(h: Any, path: str) -> None:
|
||||||
"""Feed data read from a file (to be opened by this function) into the hashlib instance."""
|
"""Feed data read from a file (to be opened by this function) into the hashlib instance."""
|
||||||
|
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
feed_file(h, f)
|
feed_file(h, f)
|
||||||
|
|
||||||
def file_digest(algorithm, path):
|
def file_digest(algorithm: Any, path: str) -> str:
|
||||||
"""Calculate the digest of a file and return it in hexadecimal notation."""
|
"""Calculate the digest of a file and return it in hexadecimal notation."""
|
||||||
|
|
||||||
h = algorithm()
|
h = algorithm()
|
||||||
feed_file_path(h, path)
|
feed_file_path(h, path)
|
||||||
return h.hexdigest()
|
return cast(str, h.hexdigest())
|
||||||
|
|
||||||
def guess_digest_algorithm(digest):
|
def guess_digest_algorithm(digest: str) -> Any:
|
||||||
l = len(digest)
|
l = len(digest)
|
||||||
if l == 32:
|
if l == 32:
|
||||||
return hashlib.md5
|
return hashlib.md5
|
||||||
@@ -36,7 +37,7 @@ def guess_digest_algorithm(digest):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def verify_file_digest(path, expected_digest):
|
def verify_file_digest(path: str, expected_digest: str) -> bool:
|
||||||
"""Verify the digest of a file, and return True if the digest matches with the given expected digest."""
|
"""Verify the digest of a file, and return True if the digest matches with the given expected digest."""
|
||||||
|
|
||||||
algorithm = guess_digest_algorithm(expected_digest)
|
algorithm = guess_digest_algorithm(expected_digest)
|
||||||
|
@@ -1,22 +1,34 @@
|
|||||||
import os.path, subprocess
|
import subprocess
|
||||||
|
from typing import Optional, Sequence, Union
|
||||||
|
|
||||||
from build.project import Project
|
from build.makeproject import MakeProject
|
||||||
|
from .toolchain import AnyToolchain
|
||||||
|
|
||||||
class ZlibProject(Project):
|
class ZlibProject(MakeProject):
|
||||||
def __init__(self, url, md5, installed,
|
def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
Project.__init__(self, url, md5, installed, **kwargs)
|
MakeProject.__init__(self, url, md5, installed, **kwargs)
|
||||||
|
|
||||||
def _build(self, toolchain):
|
def get_make_args(self, toolchain: AnyToolchain) -> list[str]:
|
||||||
|
return MakeProject.get_make_args(self, toolchain) + [
|
||||||
|
'CC=' + toolchain.cc + ' ' + toolchain.cppflags + ' ' + toolchain.cflags,
|
||||||
|
'CPP=' + toolchain.cc + ' -E ' + toolchain.cppflags,
|
||||||
|
'AR=' + toolchain.ar,
|
||||||
|
'ARFLAGS=' + toolchain.arflags,
|
||||||
|
'RANLIB=' + toolchain.ranlib,
|
||||||
|
'LDSHARED=' + toolchain.cc + ' -shared',
|
||||||
|
'libz.a'
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_make_install_args(self, toolchain: AnyToolchain) -> list[str]:
|
||||||
|
return [
|
||||||
|
'RANLIB=' + toolchain.ranlib,
|
||||||
|
self.install_target
|
||||||
|
]
|
||||||
|
|
||||||
|
def _build(self, toolchain: AnyToolchain) -> None:
|
||||||
src = self.unpack(toolchain, out_of_tree=False)
|
src = self.unpack(toolchain, out_of_tree=False)
|
||||||
|
|
||||||
subprocess.check_call(['/usr/bin/make', '--quiet',
|
subprocess.check_call(['./configure', '--prefix=' + toolchain.install_prefix, '--static'],
|
||||||
'-f', 'win32/Makefile.gcc',
|
cwd=src, env=toolchain.env)
|
||||||
'PREFIX=' + toolchain.arch + '-',
|
self.build_make(toolchain, src)
|
||||||
'-j12',
|
|
||||||
'install',
|
|
||||||
'INCLUDE_PATH='+ os.path.join(toolchain.install_prefix, 'include'),
|
|
||||||
'LIBRARY_PATH=' + os.path.join(toolchain.install_prefix, 'lib'),
|
|
||||||
'BINARY_PATH=' + os.path.join(toolchain.install_prefix, 'bin'),
|
|
||||||
],
|
|
||||||
cwd=src, env=toolchain.env)
|
|
||||||
|
@@ -352,12 +352,16 @@ ParseCommandLine(int argc, char **argv, CommandLineOptions &options,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OPTION_NO_DAEMON:
|
case OPTION_NO_DAEMON:
|
||||||
|
#ifdef ENABLE_DAEMON
|
||||||
options.daemon = false;
|
options.daemon = false;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
case OPTION_SYSTEMD:
|
case OPTION_SYSTEMD:
|
||||||
|
#ifdef ENABLE_DAEMON
|
||||||
options.daemon = false;
|
options.daemon = false;
|
||||||
|
#endif
|
||||||
options.systemd = true;
|
options.systemd = true;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -20,11 +20,18 @@
|
|||||||
#ifndef MPD_COMMAND_LINE_HXX
|
#ifndef MPD_COMMAND_LINE_HXX
|
||||||
#define MPD_COMMAND_LINE_HXX
|
#define MPD_COMMAND_LINE_HXX
|
||||||
|
|
||||||
|
#include "config.h" // for ENABLE_DAEMON
|
||||||
|
|
||||||
struct ConfigData;
|
struct ConfigData;
|
||||||
|
|
||||||
struct CommandLineOptions {
|
struct CommandLineOptions {
|
||||||
bool kill = false;
|
bool kill = false;
|
||||||
|
|
||||||
|
#ifdef ENABLE_DAEMON
|
||||||
bool daemon = true;
|
bool daemon = true;
|
||||||
|
#else
|
||||||
|
static constexpr bool daemon = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
bool systemd = false;
|
bool systemd = false;
|
||||||
|
@@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <iterator> // for std::back_inserter()
|
||||||
|
|
||||||
static constexpr Domain exception_domain("exception");
|
static constexpr Domain exception_domain("exception");
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -158,12 +158,15 @@ log_init(const ConfigData &config, bool verbose, bool use_stdout)
|
|||||||
getenv("NOTIFY_SOCKET") != nullptr) {
|
getenv("NOTIFY_SOCKET") != nullptr) {
|
||||||
/* if MPD was started as a systemd
|
/* if MPD was started as a systemd
|
||||||
service, default to journal (which
|
service, default to journal (which
|
||||||
is connected to fd=2) */
|
is connected to stdout&stderr) */
|
||||||
out_fd = STDOUT_FILENO;
|
out_fd = STDOUT_FILENO;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifndef HAVE_SYSLOG
|
#ifdef _WIN32
|
||||||
|
/* default to stdout on Windows */
|
||||||
|
out_fd = STDOUT_FILENO;
|
||||||
|
#elif !defined(HAVE_SYSLOG)
|
||||||
throw std::runtime_error("config parameter 'log_file' not found");
|
throw std::runtime_error("config parameter 'log_file' not found");
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SYSLOG
|
#ifdef HAVE_SYSLOG
|
||||||
|
@@ -482,7 +482,10 @@ MainConfigured(const CommandLineOptions &options,
|
|||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
setup_log_output();
|
setup_log_output();
|
||||||
|
|
||||||
const ScopeSignalHandlersInit signal_handlers_init(instance);
|
const ScopeSignalHandlersInit signal_handlers_init{
|
||||||
|
instance,
|
||||||
|
options.daemon,
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
instance.io_thread.Start();
|
instance.io_thread.Start();
|
||||||
|
@@ -81,6 +81,9 @@ spl_valid_name(const char *name_utf8)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
return std::strchr(name_utf8, '/') == nullptr &&
|
return std::strchr(name_utf8, '/') == nullptr &&
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::strchr(name_utf8, '\\') == nullptr &&
|
||||||
|
#endif
|
||||||
std::strchr(name_utf8, '\n') == nullptr &&
|
std::strchr(name_utf8, '\n') == nullptr &&
|
||||||
std::strchr(name_utf8, '\r') == nullptr;
|
std::strchr(name_utf8, '\r') == nullptr;
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,11 @@
|
|||||||
#include <boost/intrusive/list.hpp>
|
#include <boost/intrusive/list.hpp>
|
||||||
#include <boost/intrusive/unordered_set.hpp>
|
#include <boost/intrusive/unordered_set.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
class RemoteTagCacheHandler;
|
class RemoteTagCacheHandler;
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include "TagPrint.hxx"
|
#include "TagPrint.hxx"
|
||||||
#include "client/Response.hxx"
|
#include "client/Response.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
|
#include "lib/fmt/AudioFormatFormatter.hxx"
|
||||||
#include "time/ChronoUtil.hxx"
|
#include "time/ChronoUtil.hxx"
|
||||||
#include "util/StringBuffer.hxx"
|
#include "util/StringBuffer.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
@@ -93,7 +94,7 @@ song_print_info(Response &r, const LightSong &song, bool base) noexcept
|
|||||||
time_print(r, "Last-Modified", song.mtime);
|
time_print(r, "Last-Modified", song.mtime);
|
||||||
|
|
||||||
if (song.audio_format.IsDefined())
|
if (song.audio_format.IsDefined())
|
||||||
r.Fmt(FMT_STRING("Format: {}\n"), ToString(song.audio_format));
|
r.Fmt(FMT_STRING("Format: {}\n"), song.audio_format);
|
||||||
|
|
||||||
tag_print_values(r, song.tag);
|
tag_print_values(r, song.tag);
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ song_print_info(Response &r, const DetachedSong &song, bool base) noexcept
|
|||||||
time_print(r, "Last-Modified", song.GetLastModified());
|
time_print(r, "Last-Modified", song.GetLastModified());
|
||||||
|
|
||||||
if (const auto &f = song.GetAudioFormat(); f.IsDefined())
|
if (const auto &f = song.GetAudioFormat(); f.IsDefined())
|
||||||
r.Fmt(FMT_STRING("Format: {}\n"), ToString(f));
|
r.Fmt(FMT_STRING("Format: {}\n"), f);
|
||||||
|
|
||||||
tag_print_values(r, song.GetTag());
|
tag_print_values(r, song.GetTag());
|
||||||
|
|
||||||
|
@@ -63,6 +63,9 @@ song_save(BufferedOutputStream &os, const Song &song)
|
|||||||
if (song.audio_format.IsDefined())
|
if (song.audio_format.IsDefined())
|
||||||
os.Format("Format: %s\n", ToString(song.audio_format).c_str());
|
os.Format("Format: %s\n", ToString(song.audio_format).c_str());
|
||||||
|
|
||||||
|
if (song.in_playlist)
|
||||||
|
os.Write("InPlaylist: yes\n");
|
||||||
|
|
||||||
if (!IsNegative(song.mtime))
|
if (!IsNegative(song.mtime))
|
||||||
os.Format(SONG_MTIME ": %li\n",
|
os.Format(SONG_MTIME ": %li\n",
|
||||||
(long)std::chrono::system_clock::to_time_t(song.mtime));
|
(long)std::chrono::system_clock::to_time_t(song.mtime));
|
||||||
@@ -86,7 +89,7 @@ song_save(BufferedOutputStream &os, const DetachedSong &song)
|
|||||||
|
|
||||||
DetachedSong
|
DetachedSong
|
||||||
song_load(LineReader &file, const char *uri,
|
song_load(LineReader &file, const char *uri,
|
||||||
std::string *target_r)
|
std::string *target_r, bool *in_playlist_r)
|
||||||
{
|
{
|
||||||
DetachedSong song(uri);
|
DetachedSong song(uri);
|
||||||
|
|
||||||
@@ -132,6 +135,9 @@ song_load(LineReader &file, const char *uri,
|
|||||||
|
|
||||||
song.SetStartTime(SongTime::FromMS(start_ms));
|
song.SetStartTime(SongTime::FromMS(start_ms));
|
||||||
song.SetEndTime(SongTime::FromMS(end_ms));
|
song.SetEndTime(SongTime::FromMS(end_ms));
|
||||||
|
} else if (StringIsEqual(line, "InPlaylist")) {
|
||||||
|
if (in_playlist_r != nullptr)
|
||||||
|
*in_playlist_r = StringIsEqual(value, "yes");
|
||||||
} else {
|
} else {
|
||||||
throw FormatRuntimeError("unknown line in db: %s", line);
|
throw FormatRuntimeError("unknown line in db: %s", line);
|
||||||
}
|
}
|
||||||
|
@@ -44,6 +44,6 @@ song_save(BufferedOutputStream &os, const DetachedSong &song);
|
|||||||
*/
|
*/
|
||||||
DetachedSong
|
DetachedSong
|
||||||
song_load(LineReader &file, const char *uri,
|
song_load(LineReader &file, const char *uri,
|
||||||
std::string *target_r=nullptr);
|
std::string *target_r=nullptr, bool *in_playlist_r=nullptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -32,7 +32,7 @@ StateFileConfig::StateFileConfig(const ConfigData &config)
|
|||||||
{
|
{
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
if (path.IsNull()) {
|
if (path.IsNull()) {
|
||||||
const auto cache_dir = GetUserCacheDir();
|
const auto cache_dir = GetAppCacheDir();
|
||||||
if (cache_dir.IsNull())
|
if (cache_dir.IsNull())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@@ -35,8 +35,9 @@ tag_print_types(Response &r) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tag_print(Response &r, TagType type, StringView value) noexcept
|
tag_print(Response &r, TagType type, StringView _value) noexcept
|
||||||
{
|
{
|
||||||
|
const std::string_view value{_value};
|
||||||
r.Fmt(FMT_STRING("{}: {}\n"), tag_item_names[type], value);
|
r.Fmt(FMT_STRING("{}: {}\n"), tag_item_names[type], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,5 +36,5 @@ time_print(Response &r, const char *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Fmt(FMT_STRING("{}: {}\n"), name, s);
|
r.Fmt(FMT_STRING("{}: {}\n"), name, s.c_str());
|
||||||
}
|
}
|
||||||
|
@@ -46,7 +46,7 @@ Context::Initialise(JNIEnv *env) noexcept
|
|||||||
AllocatedPath
|
AllocatedPath
|
||||||
Context::GetExternalFilesDir(JNIEnv *env, const char *type) noexcept
|
Context::GetExternalFilesDir(JNIEnv *env, const char *type) noexcept
|
||||||
{
|
{
|
||||||
assert(_type != nullptr);
|
assert(type != nullptr);
|
||||||
|
|
||||||
jobject file = env->CallObjectMethod(Get(), getExternalFilesDir_method,
|
jobject file = env->CallObjectMethod(Get(), getExternalFilesDir_method,
|
||||||
Java::String::Optional(env, type).Get());
|
Java::String::Optional(env, type).Get());
|
||||||
|
@@ -166,7 +166,7 @@ class Iso9660InputStream final : public InputStream {
|
|||||||
assert(fill <= data.size());
|
assert(fill <= data.size());
|
||||||
assert(position <= fill);
|
assert(position <= fill);
|
||||||
|
|
||||||
return {&data[position], &data[fill]};
|
return {data.data() + position, data.data() + fill};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Consume(size_t nbytes) noexcept {
|
void Consume(size_t nbytes) noexcept {
|
||||||
|
@@ -22,6 +22,10 @@ if libzzip_dep.found()
|
|||||||
found_archive_plugin = true
|
found_archive_plugin = true
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if not found_archive_plugin
|
||||||
|
subdir_done()
|
||||||
|
endif
|
||||||
|
|
||||||
archive_plugins = static_library(
|
archive_plugins = static_library(
|
||||||
'archive_plugins',
|
'archive_plugins',
|
||||||
archive_plugins_sources,
|
archive_plugins_sources,
|
||||||
|
@@ -41,6 +41,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <limits.h> // for UINT_MAX
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
handle_listfiles_db(Client &client, Response &r, const char *uri)
|
handle_listfiles_db(Client &client, Response &r, const char *uri)
|
||||||
{
|
{
|
||||||
|
@@ -100,10 +100,6 @@ handle_listfiles_local(Response &r, Path path_fs)
|
|||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
IsValidName(const StringView s) noexcept
|
IsValidName(const StringView s) noexcept
|
||||||
@@ -130,7 +126,8 @@ public:
|
|||||||
explicit PrintCommentHandler(Response &_response) noexcept
|
explicit PrintCommentHandler(Response &_response) noexcept
|
||||||
:NullTagHandler(WANT_PAIR), response(_response) {}
|
:NullTagHandler(WANT_PAIR), response(_response) {}
|
||||||
|
|
||||||
void OnPair(StringView key, StringView value) noexcept override {
|
void OnPair(StringView _key, StringView _value) noexcept override {
|
||||||
|
const std::string_view key{_key}, value{_value};
|
||||||
if (IsValidName(key) && IsValidValue(value))
|
if (IsValidName(key) && IsValidValue(value))
|
||||||
response.Fmt(FMT_STRING("{}: {}\n"), key, value);
|
response.Fmt(FMT_STRING("{}: {}\n"), key, value);
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "Partition.hxx"
|
#include "Partition.hxx"
|
||||||
#include "Instance.hxx"
|
#include "Instance.hxx"
|
||||||
#include "IdleFlags.hxx"
|
#include "IdleFlags.hxx"
|
||||||
|
#include "lib/fmt/AudioFormatFormatter.hxx"
|
||||||
#include "util/StringBuffer.hxx"
|
#include "util/StringBuffer.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
#include "util/Exception.hxx"
|
#include "util/Exception.hxx"
|
||||||
@@ -185,7 +186,7 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r)
|
|||||||
|
|
||||||
if (player_status.audio_format.IsDefined())
|
if (player_status.audio_format.IsDefined())
|
||||||
r.Fmt(FMT_STRING(COMMAND_STATUS_AUDIO ": {}\n"),
|
r.Fmt(FMT_STRING(COMMAND_STATUS_AUDIO ": {}\n"),
|
||||||
ToString(player_status.audio_format));
|
player_status.audio_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
|
@@ -83,10 +83,6 @@ handle_listfiles_storage(Response &r, StorageDirectoryReader &reader)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
handle_listfiles_storage(Response &r, Storage &storage, const char *uri)
|
handle_listfiles_storage(Response &r, Storage &storage, const char *uri)
|
||||||
{
|
{
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include "config/Param.hxx"
|
#include "config/Param.hxx"
|
||||||
#include "config/Block.hxx"
|
#include "config/Block.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
|
#include "fs/FileSystem.hxx"
|
||||||
#include "fs/StandardDirectory.hxx"
|
#include "fs/StandardDirectory.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
|
||||||
@@ -51,17 +52,30 @@ CreateConfiguredDatabase(const ConfigData &config,
|
|||||||
} else {
|
} else {
|
||||||
/* if there is no override, use the cache directory */
|
/* if there is no override, use the cache directory */
|
||||||
|
|
||||||
const AllocatedPath cache_dir = GetUserCacheDir();
|
const AllocatedPath cache_dir = GetAppCacheDir();
|
||||||
if (cache_dir.IsNull())
|
if (cache_dir.IsNull())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
const auto db_file = cache_dir / Path::FromFS(PATH_LITERAL("mpd.db"));
|
const auto db_file = cache_dir / Path::FromFS(PATH_LITERAL("db"));
|
||||||
auto db_file_utf8 = db_file.ToUTF8();
|
auto db_file_utf8 = db_file.ToUTF8();
|
||||||
if (db_file_utf8.empty())
|
if (db_file_utf8.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ConfigBlock block;
|
ConfigBlock block;
|
||||||
block.AddBlockParam("path", std::move(db_file_utf8), -1);
|
block.AddBlockParam("path", std::move(db_file_utf8), -1);
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto mounts_dir = cache_dir
|
||||||
|
/ Path::FromFS(PATH_LITERAL("mounts"));
|
||||||
|
CreateDirectoryNoThrow(mounts_dir);
|
||||||
|
|
||||||
|
if (auto mounts_dir_utf8 = mounts_dir.ToUTF8();
|
||||||
|
!mounts_dir_utf8.empty())
|
||||||
|
block.AddBlockParam("cache_directory",
|
||||||
|
std::move(mounts_dir_utf8),
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
|
||||||
return DatabaseGlobalInit(main_event_loop, io_event_loop,
|
return DatabaseGlobalInit(main_event_loop, io_event_loop,
|
||||||
listener, block);
|
listener, block);
|
||||||
}
|
}
|
||||||
|
@@ -126,6 +126,18 @@ Directory::LookupTargetSong(std::string_view _target) noexcept
|
|||||||
return lr.directory->FindSong(lr.rest);
|
return lr.directory->FindSong(lr.rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Directory::ClearInPlaylist() noexcept
|
||||||
|
{
|
||||||
|
assert(holding_db_lock());
|
||||||
|
|
||||||
|
for (auto &child : children)
|
||||||
|
child.ClearInPlaylist();
|
||||||
|
|
||||||
|
for (auto &song : songs)
|
||||||
|
song.in_playlist = false;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Directory::PruneEmpty() noexcept
|
Directory::PruneEmpty() noexcept
|
||||||
{
|
{
|
||||||
|
@@ -287,6 +287,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
SongPtr RemoveSong(Song *song) noexcept;
|
SongPtr RemoveSong(Song *song) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively walk through the whole tree and set all
|
||||||
|
* `Song::in_playlist` fields to `false`.
|
||||||
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*/
|
||||||
|
void ClearInPlaylist() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller must lock the #db_mutex.
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
|
@@ -168,12 +168,14 @@ directory_load(LineReader &file, Directory &directory)
|
|||||||
throw FormatRuntimeError("Duplicate song '%s'", name);
|
throw FormatRuntimeError("Duplicate song '%s'", name);
|
||||||
|
|
||||||
std::string target;
|
std::string target;
|
||||||
|
bool in_playlist = false;
|
||||||
auto detached_song = song_load(file, name,
|
auto detached_song = song_load(file, name,
|
||||||
&target);
|
&target, &in_playlist);
|
||||||
|
|
||||||
auto song = std::make_unique<Song>(std::move(detached_song),
|
auto song = std::make_unique<Song>(std::move(detached_song),
|
||||||
directory);
|
directory);
|
||||||
song->target = std::move(target);
|
song->target = std::move(target);
|
||||||
|
song->in_playlist = in_playlist;
|
||||||
|
|
||||||
directory.AddSong(std::move(song));
|
directory.AddSong(std::move(song));
|
||||||
} else if ((p = StringAfterPrefix(line, PLAYLIST_META_BEGIN))) {
|
} else if ((p = StringAfterPrefix(line, PLAYLIST_META_BEGIN))) {
|
||||||
|
@@ -51,6 +51,15 @@ LockFindSong(Directory &directory, std::string_view name) noexcept
|
|||||||
return directory.FindSong(name);
|
return directory.FindSong(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
|
static bool
|
||||||
|
IsAcceptableFilename(std::string_view name) noexcept
|
||||||
|
{
|
||||||
|
return !name.empty() &&
|
||||||
|
/* newlines cannot be represented in MPD's protocol */
|
||||||
|
name.find('\n') == name.npos;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory,
|
UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory,
|
||||||
const char *name) noexcept
|
const char *name) noexcept
|
||||||
@@ -58,6 +67,9 @@ UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory,
|
|||||||
const char *tmp = std::strchr(name, '/');
|
const char *tmp = std::strchr(name, '/');
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
const std::string_view child_name(name, tmp - name);
|
const std::string_view child_name(name, tmp - name);
|
||||||
|
if (!IsAcceptableFilename(child_name))
|
||||||
|
return;
|
||||||
|
|
||||||
//add dir is not there already
|
//add dir is not there already
|
||||||
Directory *subdir = LockMakeChild(directory, child_name);
|
Directory *subdir = LockMakeChild(directory, child_name);
|
||||||
subdir->device = DEVICE_INARCHIVE;
|
subdir->device = DEVICE_INARCHIVE;
|
||||||
@@ -65,11 +77,8 @@ UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory,
|
|||||||
//create directories first
|
//create directories first
|
||||||
UpdateArchiveTree(archive, *subdir, tmp + 1);
|
UpdateArchiveTree(archive, *subdir, tmp + 1);
|
||||||
} else {
|
} else {
|
||||||
if (StringIsEmpty(name)) {
|
if (!IsAcceptableFilename(name))
|
||||||
LogWarning(update_domain,
|
|
||||||
"archive returned directory only");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
//add file
|
//add file
|
||||||
Song *song = LockFindSong(directory, name);
|
Song *song = LockFindSong(directory, name);
|
||||||
|
@@ -153,7 +153,7 @@ update_directory_stat(Storage &storage, Directory &directory) noexcept
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
FindAncestorLoop(Storage &storage, Directory *parent,
|
FindAncestorLoop(Storage &storage, Directory *parent,
|
||||||
unsigned inode, unsigned device) noexcept
|
uint64_t inode, uint64_t device) noexcept
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
if (device == 0 && inode == 0)
|
if (device == 0 && inode == 0)
|
||||||
@@ -531,6 +531,7 @@ UpdateWalk::Walk(Directory &root, const char *path, bool discard) noexcept
|
|||||||
|
|
||||||
{
|
{
|
||||||
const ScopeDatabaseLock protect;
|
const ScopeDatabaseLock protect;
|
||||||
|
root.ClearInPlaylist();
|
||||||
PurgeDanglingFromPlaylists(root);
|
PurgeDanglingFromPlaylists(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -114,11 +114,11 @@ constexpr const struct DecoderPlugin *decoder_plugins[] = {
|
|||||||
#ifdef ENABLE_ADPLUG
|
#ifdef ENABLE_ADPLUG
|
||||||
&adplug_decoder_plugin,
|
&adplug_decoder_plugin,
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_FFMPEG
|
|
||||||
&ffmpeg_decoder_plugin,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_GME
|
#ifdef ENABLE_GME
|
||||||
&gme_decoder_plugin,
|
&gme_decoder_plugin,
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_FFMPEG
|
||||||
|
&ffmpeg_decoder_plugin,
|
||||||
#endif
|
#endif
|
||||||
&pcm_decoder_plugin,
|
&pcm_decoder_plugin,
|
||||||
nullptr
|
nullptr
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#include "lib/ffmpeg/Format.hxx"
|
#include "lib/ffmpeg/Format.hxx"
|
||||||
#include "lib/ffmpeg/Codec.hxx"
|
#include "lib/ffmpeg/Codec.hxx"
|
||||||
#include "lib/ffmpeg/SampleFormat.hxx"
|
#include "lib/ffmpeg/SampleFormat.hxx"
|
||||||
|
#include "lib/ffmpeg/LibFmt.hxx"
|
||||||
#include "../DecoderAPI.hxx"
|
#include "../DecoderAPI.hxx"
|
||||||
#include "FfmpegMetaData.hxx"
|
#include "FfmpegMetaData.hxx"
|
||||||
#include "FfmpegIo.hxx"
|
#include "FfmpegIo.hxx"
|
||||||
|
@@ -26,6 +26,9 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavutil/mem.h>
|
#include <libavutil/mem.h>
|
||||||
|
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
|
||||||
|
#include <libavutil/error.h>
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
AvioStream::~AvioStream()
|
AvioStream::~AvioStream()
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample,
|
FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample,
|
||||||
unsigned channels, FLAC__uint64 total_frames)
|
unsigned channels, FLAC__uint64 total_frames) noexcept
|
||||||
{
|
{
|
||||||
assert(!initialized);
|
assert(!initialized);
|
||||||
assert(!unsupported);
|
assert(!unsupported);
|
||||||
@@ -60,7 +60,7 @@ FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FlacDecoder::OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info)
|
FlacDecoder::OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info) noexcept
|
||||||
{
|
{
|
||||||
if (initialized)
|
if (initialized)
|
||||||
return;
|
return;
|
||||||
@@ -72,7 +72,7 @@ FlacDecoder::OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc)
|
FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc) noexcept
|
||||||
{
|
{
|
||||||
ReplayGainInfo rgi;
|
ReplayGainInfo rgi;
|
||||||
if (flac_parse_replay_gain(rgi, vc))
|
if (flac_parse_replay_gain(rgi, vc))
|
||||||
@@ -86,7 +86,7 @@ FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FlacDecoder::OnMetadata(const FLAC__StreamMetadata &metadata)
|
FlacDecoder::OnMetadata(const FLAC__StreamMetadata &metadata) noexcept
|
||||||
{
|
{
|
||||||
if (unsupported)
|
if (unsupported)
|
||||||
return;
|
return;
|
||||||
@@ -106,7 +106,7 @@ FlacDecoder::OnMetadata(const FLAC__StreamMetadata &metadata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
FlacDecoder::OnFirstFrame(const FLAC__FrameHeader &header)
|
FlacDecoder::OnFirstFrame(const FLAC__FrameHeader &header) noexcept
|
||||||
{
|
{
|
||||||
if (unsupported)
|
if (unsupported)
|
||||||
return false;
|
return false;
|
||||||
@@ -139,7 +139,7 @@ FlacDecoder::GetDeltaPosition(const FLAC__StreamDecoder &sd)
|
|||||||
FLAC__StreamDecoderWriteStatus
|
FLAC__StreamDecoderWriteStatus
|
||||||
FlacDecoder::OnWrite(const FLAC__Frame &frame,
|
FlacDecoder::OnWrite(const FLAC__Frame &frame,
|
||||||
const FLAC__int32 *const buf[],
|
const FLAC__int32 *const buf[],
|
||||||
FLAC__uint64 nbytes)
|
FLAC__uint64 nbytes) noexcept
|
||||||
{
|
{
|
||||||
if (!initialized && !OnFirstFrame(frame.header))
|
if (!initialized && !OnFirstFrame(frame.header))
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
|
@@ -65,20 +65,21 @@ struct FlacDecoder : public FlacInput {
|
|||||||
*/
|
*/
|
||||||
ConstBuffer<void> chunk = nullptr;
|
ConstBuffer<void> chunk = nullptr;
|
||||||
|
|
||||||
FlacDecoder(DecoderClient &_client, InputStream &_input_stream)
|
FlacDecoder(DecoderClient &_client,
|
||||||
|
InputStream &_input_stream) noexcept
|
||||||
:FlacInput(_input_stream, &_client) {}
|
:FlacInput(_input_stream, &_client) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for DecoderClient::Ready().
|
* Wrapper for DecoderClient::Ready().
|
||||||
*/
|
*/
|
||||||
bool Initialize(unsigned sample_rate, unsigned bits_per_sample,
|
bool Initialize(unsigned sample_rate, unsigned bits_per_sample,
|
||||||
unsigned channels, FLAC__uint64 total_frames);
|
unsigned channels, FLAC__uint64 total_frames) noexcept;
|
||||||
|
|
||||||
void OnMetadata(const FLAC__StreamMetadata &metadata);
|
void OnMetadata(const FLAC__StreamMetadata &metadata) noexcept;
|
||||||
|
|
||||||
FLAC__StreamDecoderWriteStatus OnWrite(const FLAC__Frame &frame,
|
FLAC__StreamDecoderWriteStatus OnWrite(const FLAC__Frame &frame,
|
||||||
const FLAC__int32 *const buf[],
|
const FLAC__int32 *const buf[],
|
||||||
FLAC__uint64 nbytes);
|
FLAC__uint64 nbytes) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the delta (in bytes) between the last frame and
|
* Calculate the delta (in bytes) between the last frame and
|
||||||
@@ -87,8 +88,8 @@ struct FlacDecoder : public FlacInput {
|
|||||||
FLAC__uint64 GetDeltaPosition(const FLAC__StreamDecoder &sd);
|
FLAC__uint64 GetDeltaPosition(const FLAC__StreamDecoder &sd);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info);
|
void OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info) noexcept;
|
||||||
void OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc);
|
void OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function attempts to call DecoderClient::Ready() in case there
|
* This function attempts to call DecoderClient::Ready() in case there
|
||||||
@@ -97,7 +98,7 @@ private:
|
|||||||
* providing the STREAMINFO block from the beginning of the file
|
* providing the STREAMINFO block from the beginning of the file
|
||||||
* (e.g. when seeking with SqueezeBox Server).
|
* (e.g. when seeking with SqueezeBox Server).
|
||||||
*/
|
*/
|
||||||
bool OnFirstFrame(const FLAC__FrameHeader &header);
|
bool OnFirstFrame(const FLAC__FrameHeader &header) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _FLAC_COMMON_H */
|
#endif /* _FLAC_COMMON_H */
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include "lib/xiph/FlacMetadataChain.hxx"
|
#include "lib/xiph/FlacMetadataChain.hxx"
|
||||||
#include "OggCodec.hxx"
|
#include "OggCodec.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
|
#include "input/LocalOpen.hxx"
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "fs/NarrowPath.hxx"
|
#include "fs/NarrowPath.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
@@ -32,7 +33,8 @@
|
|||||||
#error libFLAC is too old
|
#error libFLAC is too old
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void flacPrintErroredState(FLAC__StreamDecoderState state)
|
static void
|
||||||
|
flacPrintErroredState(FLAC__StreamDecoderState state) noexcept
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
|
case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
|
||||||
@@ -53,8 +55,9 @@ static void flacPrintErroredState(FLAC__StreamDecoderState state)
|
|||||||
LogError(flac_domain, FLAC__StreamDecoderStateString[state]);
|
LogError(flac_domain, FLAC__StreamDecoderStateString[state]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flacMetadata([[maybe_unused]] const FLAC__StreamDecoder * dec,
|
static void
|
||||||
const FLAC__StreamMetadata * block, void *vdata)
|
flacMetadata([[maybe_unused]] const FLAC__StreamDecoder * dec,
|
||||||
|
const FLAC__StreamMetadata * block, void *vdata) noexcept
|
||||||
{
|
{
|
||||||
auto &fd = *(FlacDecoder *)vdata;
|
auto &fd = *(FlacDecoder *)vdata;
|
||||||
fd.OnMetadata(*block);
|
fd.OnMetadata(*block);
|
||||||
@@ -62,29 +65,45 @@ static void flacMetadata([[maybe_unused]] const FLAC__StreamDecoder * dec,
|
|||||||
|
|
||||||
static FLAC__StreamDecoderWriteStatus
|
static FLAC__StreamDecoderWriteStatus
|
||||||
flac_write_cb(const FLAC__StreamDecoder *dec, const FLAC__Frame *frame,
|
flac_write_cb(const FLAC__StreamDecoder *dec, const FLAC__Frame *frame,
|
||||||
const FLAC__int32 *const buf[], void *vdata)
|
const FLAC__int32 *const buf[], void *vdata) noexcept
|
||||||
{
|
{
|
||||||
auto &fd = *(FlacDecoder *)vdata;
|
auto &fd = *(FlacDecoder *)vdata;
|
||||||
return fd.OnWrite(*frame, buf, fd.GetDeltaPosition(*dec));
|
return fd.OnWrite(*frame, buf, fd.GetDeltaPosition(*dec));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
flac_scan_file(Path path_fs, TagHandler &handler)
|
flac_scan_file(Path path_fs, TagHandler &handler) noexcept {
|
||||||
{
|
|
||||||
FlacMetadataChain chain;
|
FlacMetadataChain chain;
|
||||||
if (!chain.Read(NarrowPath(path_fs))) {
|
const bool succeed = [&chain, &path_fs]() noexcept {
|
||||||
|
// read by NarrowPath
|
||||||
|
if (chain.Read(NarrowPath(path_fs))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (std::is_same_v<Path::value_type, char> ||
|
||||||
|
chain.GetStatus() != FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// read by InputStream
|
||||||
|
Mutex mutex;
|
||||||
|
auto is = OpenLocalInputStream(path_fs, mutex);
|
||||||
|
if (is && chain.Read(*is)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (!succeed) {
|
||||||
FmtDebug(flac_domain,
|
FmtDebug(flac_domain,
|
||||||
"Failed to read FLAC tags: {}",
|
"Failed to read FLAC tags: {}",
|
||||||
chain.GetStatusString());
|
chain.GetStatusString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.Scan(handler);
|
chain.Scan(handler);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
flac_scan_stream(InputStream &is, TagHandler &handler)
|
flac_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
||||||
{
|
{
|
||||||
FlacMetadataChain chain;
|
FlacMetadataChain chain;
|
||||||
if (!chain.Read(is)) {
|
if (!chain.Read(is)) {
|
||||||
@@ -102,7 +121,7 @@ flac_scan_stream(InputStream &is, TagHandler &handler)
|
|||||||
* Some glue code around FLAC__stream_decoder_new().
|
* Some glue code around FLAC__stream_decoder_new().
|
||||||
*/
|
*/
|
||||||
static FlacStreamDecoder
|
static FlacStreamDecoder
|
||||||
flac_decoder_new()
|
flac_decoder_new() noexcept
|
||||||
{
|
{
|
||||||
FlacStreamDecoder sd;
|
FlacStreamDecoder sd;
|
||||||
if(!FLAC__stream_decoder_set_metadata_respond(sd.get(), FLAC__METADATA_TYPE_VORBIS_COMMENT))
|
if(!FLAC__stream_decoder_set_metadata_respond(sd.get(), FLAC__METADATA_TYPE_VORBIS_COMMENT))
|
||||||
@@ -113,7 +132,7 @@ flac_decoder_new()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
flac_decoder_initialize(FlacDecoder *data, FLAC__StreamDecoder *sd)
|
flac_decoder_initialize(FlacDecoder *data, FLAC__StreamDecoder *sd) noexcept
|
||||||
{
|
{
|
||||||
if (!FLAC__stream_decoder_process_until_end_of_metadata(sd)) {
|
if (!FLAC__stream_decoder_process_until_end_of_metadata(sd)) {
|
||||||
if (FLAC__stream_decoder_get_state(sd) != FLAC__STREAM_DECODER_END_OF_STREAM)
|
if (FLAC__stream_decoder_get_state(sd) != FLAC__STREAM_DECODER_END_OF_STREAM)
|
||||||
@@ -231,7 +250,7 @@ flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__StreamDecoderInitStatus
|
static FLAC__StreamDecoderInitStatus
|
||||||
stream_init_oggflac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data)
|
stream_init_oggflac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data) noexcept
|
||||||
{
|
{
|
||||||
return FLAC__stream_decoder_init_ogg_stream(flac_dec,
|
return FLAC__stream_decoder_init_ogg_stream(flac_dec,
|
||||||
FlacInput::Read,
|
FlacInput::Read,
|
||||||
@@ -246,7 +265,7 @@ stream_init_oggflac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__StreamDecoderInitStatus
|
static FLAC__StreamDecoderInitStatus
|
||||||
stream_init_flac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data)
|
stream_init_flac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data) noexcept
|
||||||
{
|
{
|
||||||
return FLAC__stream_decoder_init_stream(flac_dec,
|
return FLAC__stream_decoder_init_stream(flac_dec,
|
||||||
FlacInput::Read,
|
FlacInput::Read,
|
||||||
@@ -261,7 +280,8 @@ stream_init_flac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__StreamDecoderInitStatus
|
static FLAC__StreamDecoderInitStatus
|
||||||
stream_init(FLAC__StreamDecoder *flac_dec, FlacDecoder *data, bool is_ogg)
|
stream_init(FLAC__StreamDecoder *flac_dec, FlacDecoder *data,
|
||||||
|
bool is_ogg) noexcept
|
||||||
{
|
{
|
||||||
return is_ogg
|
return is_ogg
|
||||||
? stream_init_oggflac(flac_dec, data)
|
? stream_init_oggflac(flac_dec, data)
|
||||||
@@ -307,7 +327,7 @@ flac_decode(DecoderClient &client, InputStream &input_stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
oggflac_init([[maybe_unused]] const ConfigBlock &block)
|
oggflac_init([[maybe_unused]] const ConfigBlock &block) noexcept
|
||||||
{
|
{
|
||||||
return !!FLAC_API_SUPPORTS_OGG_FLAC;
|
return !!FLAC_API_SUPPORTS_OGG_FLAC;
|
||||||
}
|
}
|
||||||
|
@@ -22,12 +22,11 @@
|
|||||||
#include "../DecoderAPI.hxx"
|
#include "../DecoderAPI.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "util/Compiler.h"
|
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
FLAC__StreamDecoderReadStatus
|
inline FLAC__StreamDecoderReadStatus
|
||||||
FlacInput::Read(FLAC__byte buffer[], size_t *bytes)
|
FlacInput::Read(FLAC__byte buffer[], size_t *bytes) noexcept
|
||||||
{
|
{
|
||||||
size_t r = decoder_read(client, input_stream, (void *)buffer, *bytes);
|
size_t r = decoder_read(client, input_stream, (void *)buffer, *bytes);
|
||||||
*bytes = r;
|
*bytes = r;
|
||||||
@@ -44,8 +43,8 @@ FlacInput::Read(FLAC__byte buffer[], size_t *bytes)
|
|||||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAC__StreamDecoderSeekStatus
|
inline FLAC__StreamDecoderSeekStatus
|
||||||
FlacInput::Seek(FLAC__uint64 absolute_byte_offset)
|
FlacInput::Seek(FLAC__uint64 absolute_byte_offset) noexcept
|
||||||
{
|
{
|
||||||
if (!input_stream.IsSeekable())
|
if (!input_stream.IsSeekable())
|
||||||
return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
|
return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
|
||||||
@@ -59,8 +58,8 @@ FlacInput::Seek(FLAC__uint64 absolute_byte_offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAC__StreamDecoderTellStatus
|
inline FLAC__StreamDecoderTellStatus
|
||||||
FlacInput::Tell(FLAC__uint64 *absolute_byte_offset)
|
FlacInput::Tell(FLAC__uint64 *absolute_byte_offset) noexcept
|
||||||
{
|
{
|
||||||
if (!input_stream.IsSeekable())
|
if (!input_stream.IsSeekable())
|
||||||
return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
|
return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
|
||||||
@@ -69,8 +68,8 @@ FlacInput::Tell(FLAC__uint64 *absolute_byte_offset)
|
|||||||
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
|
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAC__StreamDecoderLengthStatus
|
inline FLAC__StreamDecoderLengthStatus
|
||||||
FlacInput::Length(FLAC__uint64 *stream_length)
|
FlacInput::Length(FLAC__uint64 *stream_length) noexcept
|
||||||
{
|
{
|
||||||
if (!input_stream.KnownSize())
|
if (!input_stream.KnownSize())
|
||||||
return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
|
return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
|
||||||
@@ -79,8 +78,8 @@ FlacInput::Length(FLAC__uint64 *stream_length)
|
|||||||
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
|
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAC__bool
|
inline FLAC__bool
|
||||||
FlacInput::Eof()
|
FlacInput::Eof() noexcept
|
||||||
{
|
{
|
||||||
return (client != nullptr &&
|
return (client != nullptr &&
|
||||||
client->GetCommand() != DecoderCommand::NONE &&
|
client->GetCommand() != DecoderCommand::NONE &&
|
||||||
@@ -88,8 +87,8 @@ FlacInput::Eof()
|
|||||||
input_stream.LockIsEOF();
|
input_stream.LockIsEOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
inline void
|
||||||
FlacInput::Error(FLAC__StreamDecoderErrorStatus status)
|
FlacInput::Error(FLAC__StreamDecoderErrorStatus status) noexcept
|
||||||
{
|
{
|
||||||
if (client == nullptr ||
|
if (client == nullptr ||
|
||||||
client->GetCommand() != DecoderCommand::STOP)
|
client->GetCommand() != DecoderCommand::STOP)
|
||||||
@@ -100,7 +99,7 @@ FlacInput::Error(FLAC__StreamDecoderErrorStatus status)
|
|||||||
FLAC__StreamDecoderReadStatus
|
FLAC__StreamDecoderReadStatus
|
||||||
FlacInput::Read([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
FlacInput::Read([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
||||||
FLAC__byte buffer[], size_t *bytes,
|
FLAC__byte buffer[], size_t *bytes,
|
||||||
void *client_data)
|
void *client_data) noexcept
|
||||||
{
|
{
|
||||||
auto *i = (FlacInput *)client_data;
|
auto *i = (FlacInput *)client_data;
|
||||||
|
|
||||||
@@ -109,7 +108,7 @@ FlacInput::Read([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
|||||||
|
|
||||||
FLAC__StreamDecoderSeekStatus
|
FLAC__StreamDecoderSeekStatus
|
||||||
FlacInput::Seek([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
FlacInput::Seek([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
||||||
FLAC__uint64 absolute_byte_offset, void *client_data)
|
FLAC__uint64 absolute_byte_offset, void *client_data) noexcept
|
||||||
{
|
{
|
||||||
auto *i = (FlacInput *)client_data;
|
auto *i = (FlacInput *)client_data;
|
||||||
|
|
||||||
@@ -118,7 +117,7 @@ FlacInput::Seek([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
|||||||
|
|
||||||
FLAC__StreamDecoderTellStatus
|
FLAC__StreamDecoderTellStatus
|
||||||
FlacInput::Tell([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
FlacInput::Tell([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
||||||
FLAC__uint64 *absolute_byte_offset, void *client_data)
|
FLAC__uint64 *absolute_byte_offset, void *client_data) noexcept
|
||||||
{
|
{
|
||||||
auto *i = (FlacInput *)client_data;
|
auto *i = (FlacInput *)client_data;
|
||||||
|
|
||||||
@@ -127,7 +126,7 @@ FlacInput::Tell([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
|||||||
|
|
||||||
FLAC__StreamDecoderLengthStatus
|
FLAC__StreamDecoderLengthStatus
|
||||||
FlacInput::Length([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
FlacInput::Length([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
||||||
FLAC__uint64 *stream_length, void *client_data)
|
FLAC__uint64 *stream_length, void *client_data) noexcept
|
||||||
{
|
{
|
||||||
auto *i = (FlacInput *)client_data;
|
auto *i = (FlacInput *)client_data;
|
||||||
|
|
||||||
@@ -136,7 +135,7 @@ FlacInput::Length([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
|||||||
|
|
||||||
FLAC__bool
|
FLAC__bool
|
||||||
FlacInput::Eof([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
FlacInput::Eof([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
||||||
void *client_data)
|
void *client_data) noexcept
|
||||||
{
|
{
|
||||||
auto *i = (FlacInput *)client_data;
|
auto *i = (FlacInput *)client_data;
|
||||||
|
|
||||||
@@ -145,7 +144,8 @@ FlacInput::Eof([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
|
|||||||
|
|
||||||
void
|
void
|
||||||
FlacInput::Error([[maybe_unused]] const FLAC__StreamDecoder *decoder,
|
FlacInput::Error([[maybe_unused]] const FLAC__StreamDecoder *decoder,
|
||||||
FLAC__StreamDecoderErrorStatus status, void *client_data)
|
FLAC__StreamDecoderErrorStatus status,
|
||||||
|
void *client_data) noexcept
|
||||||
{
|
{
|
||||||
auto *i = (FlacInput *)client_data;
|
auto *i = (FlacInput *)client_data;
|
||||||
|
|
||||||
|
@@ -48,36 +48,38 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FLAC__StreamDecoderReadStatus Read(FLAC__byte buffer[], size_t *bytes);
|
FLAC__StreamDecoderReadStatus Read(FLAC__byte buffer[], size_t *bytes) noexcept;
|
||||||
FLAC__StreamDecoderSeekStatus Seek(FLAC__uint64 absolute_byte_offset);
|
FLAC__StreamDecoderSeekStatus Seek(FLAC__uint64 absolute_byte_offset) noexcept;
|
||||||
FLAC__StreamDecoderTellStatus Tell(FLAC__uint64 *absolute_byte_offset);
|
FLAC__StreamDecoderTellStatus Tell(FLAC__uint64 *absolute_byte_offset) noexcept;
|
||||||
FLAC__StreamDecoderLengthStatus Length(FLAC__uint64 *stream_length);
|
FLAC__StreamDecoderLengthStatus Length(FLAC__uint64 *stream_length) noexcept;
|
||||||
FLAC__bool Eof();
|
FLAC__bool Eof() noexcept;
|
||||||
void Error(FLAC__StreamDecoderErrorStatus status);
|
void Error(FLAC__StreamDecoderErrorStatus status) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FLAC__StreamDecoderReadStatus
|
static FLAC__StreamDecoderReadStatus
|
||||||
Read(const FLAC__StreamDecoder *flac_decoder,
|
Read(const FLAC__StreamDecoder *flac_decoder,
|
||||||
FLAC__byte buffer[], size_t *bytes, void *client_data);
|
FLAC__byte buffer[], size_t *bytes, void *client_data) noexcept;
|
||||||
|
|
||||||
static FLAC__StreamDecoderSeekStatus
|
static FLAC__StreamDecoderSeekStatus
|
||||||
Seek(const FLAC__StreamDecoder *flac_decoder,
|
Seek(const FLAC__StreamDecoder *flac_decoder,
|
||||||
FLAC__uint64 absolute_byte_offset, void *client_data);
|
FLAC__uint64 absolute_byte_offset, void *client_data) noexcept;
|
||||||
|
|
||||||
static FLAC__StreamDecoderTellStatus
|
static FLAC__StreamDecoderTellStatus
|
||||||
Tell(const FLAC__StreamDecoder *flac_decoder,
|
Tell(const FLAC__StreamDecoder *flac_decoder,
|
||||||
FLAC__uint64 *absolute_byte_offset, void *client_data);
|
FLAC__uint64 *absolute_byte_offset, void *client_data) noexcept;
|
||||||
|
|
||||||
static FLAC__StreamDecoderLengthStatus
|
static FLAC__StreamDecoderLengthStatus
|
||||||
Length(const FLAC__StreamDecoder *flac_decoder,
|
Length(const FLAC__StreamDecoder *flac_decoder,
|
||||||
FLAC__uint64 *stream_length, void *client_data);
|
FLAC__uint64 *stream_length, void *client_data) noexcept;
|
||||||
|
|
||||||
static FLAC__bool
|
static FLAC__bool
|
||||||
Eof(const FLAC__StreamDecoder *flac_decoder, void *client_data);
|
Eof(const FLAC__StreamDecoder *flac_decoder,
|
||||||
|
void *client_data) noexcept;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Error(const FLAC__StreamDecoder *decoder,
|
Error(const FLAC__StreamDecoder *decoder,
|
||||||
FLAC__StreamDecoderErrorStatus status, void *client_data);
|
FLAC__StreamDecoderErrorStatus status,
|
||||||
|
void *client_data) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -39,7 +39,8 @@ FlacPcmImport::Open(unsigned sample_rate, unsigned bits_per_sample,
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void
|
static void
|
||||||
FlacImportStereo(T *dest, const FLAC__int32 *const src[], size_t n_frames)
|
FlacImportStereo(T *dest, const FLAC__int32 *const src[],
|
||||||
|
size_t n_frames) noexcept
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i != n_frames; ++i) {
|
for (size_t i = 0; i != n_frames; ++i) {
|
||||||
*dest++ = (T)src[0][i];
|
*dest++ = (T)src[0][i];
|
||||||
@@ -50,7 +51,7 @@ FlacImportStereo(T *dest, const FLAC__int32 *const src[], size_t n_frames)
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static void
|
static void
|
||||||
FlacImportAny(T *dest, const FLAC__int32 *const src[], size_t n_frames,
|
FlacImportAny(T *dest, const FLAC__int32 *const src[], size_t n_frames,
|
||||||
unsigned n_channels)
|
unsigned n_channels) noexcept
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i != n_frames; ++i)
|
for (size_t i = 0; i != n_frames; ++i)
|
||||||
for (unsigned c = 0; c != n_channels; ++c)
|
for (unsigned c = 0; c != n_channels; ++c)
|
||||||
@@ -60,7 +61,7 @@ FlacImportAny(T *dest, const FLAC__int32 *const src[], size_t n_frames,
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static void
|
static void
|
||||||
FlacImport(T *dest, const FLAC__int32 *const src[], size_t n_frames,
|
FlacImport(T *dest, const FLAC__int32 *const src[], size_t n_frames,
|
||||||
unsigned n_channels)
|
unsigned n_channels) noexcept
|
||||||
{
|
{
|
||||||
if (n_channels == 2)
|
if (n_channels == 2)
|
||||||
FlacImportStereo(dest, src, n_frames);
|
FlacImportStereo(dest, src, n_frames);
|
||||||
@@ -71,7 +72,7 @@ FlacImport(T *dest, const FLAC__int32 *const src[], size_t n_frames,
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static ConstBuffer<void>
|
static ConstBuffer<void>
|
||||||
FlacImport(PcmBuffer &buffer, const FLAC__int32 *const src[], size_t n_frames,
|
FlacImport(PcmBuffer &buffer, const FLAC__int32 *const src[], size_t n_frames,
|
||||||
unsigned n_channels)
|
unsigned n_channels) noexcept
|
||||||
{
|
{
|
||||||
size_t n_samples = n_frames * n_channels;
|
size_t n_samples = n_frames * n_channels;
|
||||||
size_t dest_size = n_samples * sizeof(T);
|
size_t dest_size = n_samples * sizeof(T);
|
||||||
|
@@ -43,7 +43,7 @@ public:
|
|||||||
void Open(unsigned sample_rate, unsigned bits_per_sample,
|
void Open(unsigned sample_rate, unsigned bits_per_sample,
|
||||||
unsigned channels);
|
unsigned channels);
|
||||||
|
|
||||||
const AudioFormat &GetAudioFormat() const {
|
const AudioFormat &GetAudioFormat() const noexcept {
|
||||||
return audio_format;
|
return audio_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -56,20 +56,17 @@ struct GmeContainerPath {
|
|||||||
unsigned track;
|
unsigned track;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if GME_VERSION >= 0x000600
|
|
||||||
static int gme_accuracy;
|
static int gme_accuracy;
|
||||||
#endif
|
|
||||||
static unsigned gme_default_fade;
|
static unsigned gme_default_fade;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
gme_plugin_init([[maybe_unused]] const ConfigBlock &block)
|
gme_plugin_init([[maybe_unused]] const ConfigBlock &block)
|
||||||
{
|
{
|
||||||
#if GME_VERSION >= 0x000600
|
|
||||||
auto accuracy = block.GetBlockParam("accuracy");
|
auto accuracy = block.GetBlockParam("accuracy");
|
||||||
gme_accuracy = accuracy != nullptr
|
gme_accuracy = accuracy != nullptr
|
||||||
? (int)accuracy->GetBoolValue()
|
? (int)accuracy->GetBoolValue()
|
||||||
: -1;
|
: -1;
|
||||||
#endif
|
|
||||||
auto fade = block.GetBlockParam("default_fade");
|
auto fade = block.GetBlockParam("default_fade");
|
||||||
gme_default_fade = fade != nullptr
|
gme_default_fade = fade != nullptr
|
||||||
? fade->GetUnsignedValue() * 1000
|
? fade->GetUnsignedValue() * 1000
|
||||||
@@ -163,10 +160,8 @@ gme_file_decode(DecoderClient &client, Path path_fs)
|
|||||||
FmtDebug(gme_domain, "emulator type '{}'",
|
FmtDebug(gme_domain, "emulator type '{}'",
|
||||||
gme_type_system(gme_type(emu)));
|
gme_type_system(gme_type(emu)));
|
||||||
|
|
||||||
#if GME_VERSION >= 0x000600
|
|
||||||
if (gme_accuracy >= 0)
|
if (gme_accuracy >= 0)
|
||||||
gme_enable_accuracy(emu, gme_accuracy);
|
gme_enable_accuracy(emu, gme_accuracy);
|
||||||
#endif
|
|
||||||
|
|
||||||
gme_info_t *ti;
|
gme_info_t *ti;
|
||||||
const char *gme_err = gme_track_info(emu, &ti, container.track);
|
const char *gme_err = gme_track_info(emu, &ti, container.track);
|
||||||
|
@@ -562,7 +562,21 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) noexcept
|
|||||||
|
|
||||||
mad_bit_skip(ptr, 16);
|
mad_bit_skip(ptr, 16);
|
||||||
|
|
||||||
lame->peak = MAD_F(mad_bit_read(ptr, 32) << 5); /* peak */
|
/* The lame peak value is a float multiplied by 2^23 and stored as an
|
||||||
|
* unsigned integer (it is always positive). MAD's fixed-point format uses
|
||||||
|
* 28 bits for the fractional part, so shift the 23 bit fraction up before
|
||||||
|
* converting to a float.
|
||||||
|
*/
|
||||||
|
unsigned long peak_int = mad_bit_read(ptr, 32);
|
||||||
|
|
||||||
|
#define LAME_PEAK_FRACBITS 23
|
||||||
|
#if MAD_F_FRACBITS > LAME_PEAK_FRACBITS
|
||||||
|
peak_int <<= (MAD_F_FRACBITS - LAME_PEAK_FRACBITS);
|
||||||
|
#elif LAME_PEAK_FRACBITS > MAD_F_FRACBITS
|
||||||
|
peak_int >>= (LAME_PEAK_FRACBITS - MAD_F_FRACBITS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lame->peak = mad_f_todouble(peak_int); /* peak */
|
||||||
FmtDebug(mad_domain, "LAME peak found: {}", lame->peak);
|
FmtDebug(mad_domain, "LAME peak found: {}", lame->peak);
|
||||||
|
|
||||||
lame->track_gain = 0;
|
lame->track_gain = 0;
|
||||||
@@ -798,6 +812,8 @@ MadDecoder::UpdateTimerNextFrame() noexcept
|
|||||||
DecoderCommand
|
DecoderCommand
|
||||||
MadDecoder::SubmitPCM(size_t i, size_t pcm_length) noexcept
|
MadDecoder::SubmitPCM(size_t i, size_t pcm_length) noexcept
|
||||||
{
|
{
|
||||||
|
assert(i <= pcm_length);
|
||||||
|
|
||||||
size_t num_samples = pcm_length - i;
|
size_t num_samples = pcm_length - i;
|
||||||
|
|
||||||
mad_fixed_to_24_buffer(output_buffer, synth.pcm,
|
mad_fixed_to_24_buffer(output_buffer, synth.pcm,
|
||||||
@@ -843,7 +859,7 @@ MadDecoder::SynthAndSubmit() noexcept
|
|||||||
size_t pcm_length = synth.pcm.length;
|
size_t pcm_length = synth.pcm.length;
|
||||||
if (drop_end_samples &&
|
if (drop_end_samples &&
|
||||||
current_frame == max_frames - drop_end_frames - 1) {
|
current_frame == max_frames - drop_end_frames - 1) {
|
||||||
if (drop_end_samples >= pcm_length)
|
if (i + drop_end_samples >= pcm_length)
|
||||||
return DecoderCommand::STOP;
|
return DecoderCommand::STOP;
|
||||||
|
|
||||||
pcm_length -= drop_end_samples;
|
pcm_length -= drop_end_samples;
|
||||||
|
@@ -81,7 +81,7 @@ if libfaad_dep.found()
|
|||||||
decoder_plugins_sources += 'FaadDecoderPlugin.cxx'
|
decoder_plugins_sources += 'FaadDecoderPlugin.cxx'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libgme_dep = c_compiler.find_library('gme', required: get_option('gme'))
|
libgme_dep = dependency('libgme', version: '>= 0.6', required: get_option('gme'))
|
||||||
decoder_features.set('ENABLE_GME', libgme_dep.found())
|
decoder_features.set('ENABLE_GME', libgme_dep.found())
|
||||||
if libgme_dep.found()
|
if libgme_dep.found()
|
||||||
decoder_plugins_sources += 'GmeDecoderPlugin.cxx'
|
decoder_plugins_sources += 'GmeDecoderPlugin.cxx'
|
||||||
|
@@ -38,6 +38,7 @@ class FlacEncoder final : public Encoder {
|
|||||||
|
|
||||||
FLAC__StreamEncoder *const fse;
|
FLAC__StreamEncoder *const fse;
|
||||||
const unsigned compression;
|
const unsigned compression;
|
||||||
|
const bool oggflac;
|
||||||
|
|
||||||
PcmBuffer expand_buffer;
|
PcmBuffer expand_buffer;
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ flac_encoder_init(const ConfigBlock &block)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
flac_encoder_setup(FLAC__StreamEncoder *fse, unsigned compression,
|
flac_encoder_setup(FLAC__StreamEncoder *fse, unsigned compression, bool oggflac,
|
||||||
const AudioFormat &audio_format)
|
const AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
unsigned bits_per_sample;
|
unsigned bits_per_sample;
|
||||||
@@ -157,7 +158,7 @@ flac_encoder_setup(FLAC__StreamEncoder *fse, unsigned compression,
|
|||||||
throw FormatRuntimeError("error setting flac sample rate to %d",
|
throw FormatRuntimeError("error setting flac sample rate to %d",
|
||||||
audio_format.sample_rate);
|
audio_format.sample_rate);
|
||||||
|
|
||||||
if (!FLAC__stream_encoder_set_ogg_serial_number(fse,
|
if (oggflac && !FLAC__stream_encoder_set_ogg_serial_number(fse,
|
||||||
GenerateSerial()))
|
GenerateSerial()))
|
||||||
throw FormatRuntimeError("error setting ogg serial number");
|
throw FormatRuntimeError("error setting ogg serial number");
|
||||||
}
|
}
|
||||||
@@ -166,11 +167,12 @@ FlacEncoder::FlacEncoder(AudioFormat _audio_format, FLAC__StreamEncoder *_fse, u
|
|||||||
:Encoder(_oggchaining),
|
:Encoder(_oggchaining),
|
||||||
audio_format(_audio_format), fse(_fse),
|
audio_format(_audio_format), fse(_fse),
|
||||||
compression(_compression),
|
compression(_compression),
|
||||||
|
oggflac(_oggflac),
|
||||||
output_buffer(8192)
|
output_buffer(8192)
|
||||||
{
|
{
|
||||||
/* this immediately outputs data through callback */
|
/* this immediately outputs data through callback */
|
||||||
|
|
||||||
auto init_status = _oggflac ?
|
auto init_status = oggflac ?
|
||||||
FLAC__stream_encoder_init_ogg_stream(fse,
|
FLAC__stream_encoder_init_ogg_stream(fse,
|
||||||
nullptr, WriteCallback,
|
nullptr, WriteCallback,
|
||||||
nullptr, nullptr, nullptr,
|
nullptr, nullptr, nullptr,
|
||||||
@@ -209,7 +211,7 @@ PreparedFlacEncoder::Open(AudioFormat &audio_format)
|
|||||||
throw std::runtime_error("FLAC__stream_encoder_new() failed");
|
throw std::runtime_error("FLAC__stream_encoder_new() failed");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
flac_encoder_setup(fse, compression, audio_format);
|
flac_encoder_setup(fse, compression, oggflac, audio_format);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
FLAC__stream_encoder_delete(fse);
|
FLAC__stream_encoder_delete(fse);
|
||||||
throw;
|
throw;
|
||||||
@@ -222,7 +224,7 @@ void
|
|||||||
FlacEncoder::SendTag(const Tag &tag)
|
FlacEncoder::SendTag(const Tag &tag)
|
||||||
{
|
{
|
||||||
/* re-initialize encoder since flac_encoder_finish resets everything */
|
/* re-initialize encoder since flac_encoder_finish resets everything */
|
||||||
flac_encoder_setup(fse, compression, audio_format);
|
flac_encoder_setup(fse, compression, oggflac, audio_format);
|
||||||
|
|
||||||
FLAC__StreamMetadata *metadata = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
FLAC__StreamMetadata *metadata = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||||
|
@@ -272,9 +272,8 @@ EventLoop::Run() noexcept
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(IsInside());
|
assert(IsInside());
|
||||||
assert(!quit);
|
|
||||||
#ifdef HAVE_THREADED_EVENT_LOOP
|
#ifdef HAVE_THREADED_EVENT_LOOP
|
||||||
assert(alive);
|
assert(alive || quit);
|
||||||
assert(busy);
|
assert(busy);
|
||||||
|
|
||||||
wake_event.Schedule(SocketEvent::READ);
|
wake_event.Schedule(SocketEvent::READ);
|
||||||
@@ -299,7 +298,7 @@ EventLoop::Run() noexcept
|
|||||||
|
|
||||||
steady_clock_cache.flush();
|
steady_clock_cache.flush();
|
||||||
|
|
||||||
do {
|
while (!quit) {
|
||||||
again = false;
|
again = false;
|
||||||
|
|
||||||
/* invoke timers */
|
/* invoke timers */
|
||||||
@@ -361,7 +360,7 @@ EventLoop::Run() noexcept
|
|||||||
|
|
||||||
socket_event.Dispatch();
|
socket_event.Dispatch();
|
||||||
}
|
}
|
||||||
} while (!quit);
|
}
|
||||||
|
|
||||||
#ifdef HAVE_THREADED_EVENT_LOOP
|
#ifdef HAVE_THREADED_EVENT_LOOP
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@@ -66,6 +66,9 @@ FfmpegFilter::FilterPCM(ConstBuffer<void> src)
|
|||||||
#endif
|
#endif
|
||||||
frame->nb_samples = src.size / in_audio_frame_size;
|
frame->nb_samples = src.size / in_audio_frame_size;
|
||||||
|
|
||||||
|
frame->pts = pts;
|
||||||
|
pts += frame->nb_samples;
|
||||||
|
|
||||||
frame.GetBuffer();
|
frame.GetBuffer();
|
||||||
|
|
||||||
memcpy(frame.GetData(0), src.data, src.size);
|
memcpy(frame.GetData(0), src.data, src.size);
|
||||||
|
@@ -17,14 +17,15 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MPD_FFMPEG_FILTER__HXX
|
#pragma once
|
||||||
#define MPD_FFMPEG_FILTER__HXX
|
|
||||||
|
|
||||||
#include "filter/Filter.hxx"
|
#include "filter/Filter.hxx"
|
||||||
#include "lib/ffmpeg/Buffer.hxx"
|
#include "lib/ffmpeg/Buffer.hxx"
|
||||||
#include "lib/ffmpeg/Filter.hxx"
|
#include "lib/ffmpeg/Filter.hxx"
|
||||||
#include "lib/ffmpeg/Frame.hxx"
|
#include "lib/ffmpeg/Frame.hxx"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A #Filter implementation using FFmpeg's libavfilter.
|
* A #Filter implementation using FFmpeg's libavfilter.
|
||||||
*/
|
*/
|
||||||
@@ -46,6 +47,11 @@ class FfmpegFilter final : public Filter {
|
|||||||
const size_t in_audio_frame_size;
|
const size_t in_audio_frame_size;
|
||||||
const size_t out_audio_frame_size;
|
const size_t out_audio_frame_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Presentation timestamp. A counter for `AVFrame::pts`.
|
||||||
|
*/
|
||||||
|
int_least64_t pts = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @param _graph a checked and configured AVFilterGraph
|
* @param _graph a checked and configured AVFilterGraph
|
||||||
@@ -63,5 +69,3 @@ public:
|
|||||||
/* virtual methods from class Filter */
|
/* virtual methods from class Filter */
|
||||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@@ -20,7 +20,6 @@
|
|||||||
#include "Charset.hxx"
|
#include "Charset.hxx"
|
||||||
#include "Features.hxx"
|
#include "Features.hxx"
|
||||||
#include "Domain.hxx"
|
#include "Domain.hxx"
|
||||||
#include "Log.hxx"
|
|
||||||
#include "lib/icu/Converter.hxx"
|
#include "lib/icu/Converter.hxx"
|
||||||
#include "util/AllocatedString.hxx"
|
#include "util/AllocatedString.hxx"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -45,11 +44,9 @@ SetFSCharset(const char *charset)
|
|||||||
assert(charset != nullptr);
|
assert(charset != nullptr);
|
||||||
assert(fs_converter == nullptr);
|
assert(fs_converter == nullptr);
|
||||||
|
|
||||||
|
fs_charset = charset;
|
||||||
fs_converter = IcuConverter::Create(charset);
|
fs_converter = IcuConverter::Create(charset);
|
||||||
assert(fs_converter != nullptr);
|
assert(fs_converter != nullptr);
|
||||||
|
|
||||||
FmtDebug(path_domain,
|
|
||||||
"SetFSCharset: fs charset is {}", fs_charset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -67,6 +67,16 @@ StatFile(Path file, struct stat &buf, bool follow_symlinks = true)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
CreateDirectoryNoThrow(Path path) noexcept
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return CreateDirectory(path.c_str(), nullptr);
|
||||||
|
#else
|
||||||
|
return mkdir(path.c_str(), 0777);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Truncate a file that exists already. Throws std::system_error on
|
* Truncate a file that exists already. Throws std::system_error on
|
||||||
* error.
|
* error.
|
||||||
|
@@ -34,7 +34,6 @@
|
|||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#else
|
#else
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -53,6 +52,12 @@
|
|||||||
#include "Main.hxx"
|
#include "Main.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_XDG
|
||||||
|
#include "Version.h" // for PACKAGE_NAME
|
||||||
|
#define APP_FILENAME PATH_LITERAL(PACKAGE_NAME)
|
||||||
|
static constexpr Path app_filename = Path::FromFS(APP_FILENAME);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(ANDROID)
|
#if !defined(_WIN32) && !defined(ANDROID)
|
||||||
class PasswdEntry
|
class PasswdEntry
|
||||||
{
|
{
|
||||||
@@ -74,15 +79,6 @@ public:
|
|||||||
return result != nullptr;
|
return result != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadByUid(uid_t uid) {
|
|
||||||
#ifdef HAVE_GETPWUID_R
|
|
||||||
getpwuid_r(uid, &pw, buf.data(), buf.size(), &result);
|
|
||||||
#else
|
|
||||||
result = getpwuid(uid);
|
|
||||||
#endif
|
|
||||||
return result != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const passwd *operator->() {
|
const passwd *operator->() {
|
||||||
assert(result != nullptr);
|
assert(result != nullptr);
|
||||||
return result;
|
return result;
|
||||||
@@ -284,6 +280,24 @@ GetUserCacheDir() noexcept
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AllocatedPath
|
||||||
|
GetAppCacheDir() noexcept
|
||||||
|
{
|
||||||
|
#ifdef USE_XDG
|
||||||
|
if (const auto user_dir = GetUserCacheDir(); !user_dir.IsNull()) {
|
||||||
|
auto dir = user_dir / app_filename;
|
||||||
|
CreateDirectoryNoThrow(dir);
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
#elif defined(ANDROID)
|
||||||
|
return context->GetCacheDir(Java::GetEnv());
|
||||||
|
#else
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
AllocatedPath
|
AllocatedPath
|
||||||
GetUserRuntimeDir() noexcept
|
GetUserRuntimeDir() noexcept
|
||||||
{
|
{
|
||||||
@@ -297,7 +311,7 @@ GetUserRuntimeDir() noexcept
|
|||||||
AllocatedPath
|
AllocatedPath
|
||||||
GetAppRuntimeDir() noexcept
|
GetAppRuntimeDir() noexcept
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#if defined(__linux__) && !defined(ANDROID)
|
||||||
/* systemd specific; see systemd.exec(5) */
|
/* systemd specific; see systemd.exec(5) */
|
||||||
if (const char *runtime_directory = getenv("RUNTIME_DIRECTORY"))
|
if (const char *runtime_directory = getenv("RUNTIME_DIRECTORY"))
|
||||||
if (auto dir = StringView{runtime_directory}.Split(':').first;
|
if (auto dir = StringView{runtime_directory}.Split(':').first;
|
||||||
@@ -307,8 +321,8 @@ GetAppRuntimeDir() noexcept
|
|||||||
|
|
||||||
#ifdef USE_XDG
|
#ifdef USE_XDG
|
||||||
if (const auto user_dir = GetUserRuntimeDir(); !user_dir.IsNull()) {
|
if (const auto user_dir = GetUserRuntimeDir(); !user_dir.IsNull()) {
|
||||||
auto dir = user_dir / Path::FromFS("mpd");
|
auto dir = user_dir / app_filename;
|
||||||
mkdir(dir.c_str(), 0700);
|
CreateDirectoryNoThrow(dir);
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -351,10 +365,8 @@ GetHomeDir() noexcept
|
|||||||
if (const auto home = getenv("HOME");
|
if (const auto home = getenv("HOME");
|
||||||
IsValidPathString(home) && IsValidDir(home))
|
IsValidPathString(home) && IsValidDir(home))
|
||||||
return AllocatedPath::FromFS(home);
|
return AllocatedPath::FromFS(home);
|
||||||
|
|
||||||
if (PasswdEntry pw; pw.ReadByUid(getuid()))
|
|
||||||
return SafePathFromFS(pw->pw_dir);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -43,6 +43,13 @@ GetUserMusicDir() noexcept;
|
|||||||
AllocatedPath
|
AllocatedPath
|
||||||
GetUserCacheDir() noexcept;
|
GetUserCacheDir() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains cache directory for this application.
|
||||||
|
*/
|
||||||
|
[[gnu::const]]
|
||||||
|
AllocatedPath
|
||||||
|
GetAppCacheDir() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the runtime directory for the current user.
|
* Obtains the runtime directory for the current user.
|
||||||
*/
|
*/
|
||||||
|
@@ -101,9 +101,17 @@ AsyncInputStream::Seek(std::unique_lock<Mutex> &lock,
|
|||||||
assert(IsReady());
|
assert(IsReady());
|
||||||
assert(seek_state == SeekState::NONE);
|
assert(seek_state == SeekState::NONE);
|
||||||
|
|
||||||
if (new_offset == offset)
|
if (new_offset == offset) {
|
||||||
/* no-op */
|
/* no-op, but if the stream is not open anymore (maybe
|
||||||
|
because it has failed), nothing can be read, so we
|
||||||
|
should check for errors here instead of pretending
|
||||||
|
everything's fine */
|
||||||
|
|
||||||
|
if (!open)
|
||||||
|
Check();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsSeekable())
|
if (!IsSeekable())
|
||||||
throw std::runtime_error("Not seekable");
|
throw std::runtime_error("Not seekable");
|
||||||
|
@@ -234,7 +234,7 @@ AlsaInputStream::PrepareSockets() noexcept
|
|||||||
|
|
||||||
void
|
void
|
||||||
AlsaInputStream::DispatchSockets() noexcept
|
AlsaInputStream::DispatchSockets() noexcept
|
||||||
{
|
try {
|
||||||
non_block.DispatchSockets(*this, capture_handle);
|
non_block.DispatchSockets(*this, capture_handle);
|
||||||
|
|
||||||
const std::scoped_lock<Mutex> protect(mutex);
|
const std::scoped_lock<Mutex> protect(mutex);
|
||||||
@@ -253,16 +253,17 @@ AlsaInputStream::DispatchSockets() noexcept
|
|||||||
if (n_frames == -EAGAIN)
|
if (n_frames == -EAGAIN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Recover(n_frames) < 0) {
|
if (Recover(n_frames) < 0)
|
||||||
postponed_exception = std::make_exception_ptr(std::runtime_error("PCM error - stream aborted"));
|
throw std::runtime_error("PCM error - stream aborted");
|
||||||
InvokeOnAvailable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nbytes = n_frames * frame_size;
|
size_t nbytes = n_frames * frame_size;
|
||||||
CommitWriteBuffer(nbytes);
|
CommitWriteBuffer(nbytes);
|
||||||
}
|
}
|
||||||
|
catch (...) {
|
||||||
|
postponed_exception = std::current_exception();
|
||||||
|
InvokeOnAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
inline int
|
inline int
|
||||||
AlsaInputStream::Recover(int err)
|
AlsaInputStream::Recover(int err)
|
||||||
@@ -369,9 +370,14 @@ AlsaInputStream::ConfigureCapture(AudioFormat audio_format)
|
|||||||
period_size_min, period_size_max,
|
period_size_min, period_size_max,
|
||||||
period_time_min, period_time_max);
|
period_time_min, period_time_max);
|
||||||
|
|
||||||
/* choose the maximum possible buffer_size ... */
|
/* choose the maximum buffer_time up to limit of 2 seconds ... */
|
||||||
snd_pcm_hw_params_set_buffer_size(capture_handle, hw_params,
|
unsigned buffer_time = buffer_time_max;
|
||||||
buffer_size_max);
|
if (buffer_time > 2000000U)
|
||||||
|
buffer_time = 2000000U;
|
||||||
|
int direction = -1;
|
||||||
|
if ((err = snd_pcm_hw_params_set_buffer_time_near(capture_handle,
|
||||||
|
hw_params, &buffer_time, &direction)) < 0)
|
||||||
|
throw Alsa::MakeError(err, "Cannot set buffer time");
|
||||||
|
|
||||||
/* ... and calculate the period_size to have four periods in
|
/* ... and calculate the period_size to have four periods in
|
||||||
one buffer; this way, we get woken up often enough to avoid
|
one buffer; this way, we get woken up often enough to avoid
|
||||||
@@ -379,7 +385,7 @@ AlsaInputStream::ConfigureCapture(AudioFormat audio_format)
|
|||||||
snd_pcm_uframes_t buffer_size;
|
snd_pcm_uframes_t buffer_size;
|
||||||
if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) == 0) {
|
if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) == 0) {
|
||||||
snd_pcm_uframes_t period_size = buffer_size / 4;
|
snd_pcm_uframes_t period_size = buffer_size / 4;
|
||||||
int direction = -1;
|
direction = -1;
|
||||||
if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle,
|
if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle,
|
||||||
hw_params, &period_size, &direction)) < 0)
|
hw_params, &period_size, &direction)) < 0)
|
||||||
throw Alsa::MakeError(err, "Cannot set period size");
|
throw Alsa::MakeError(err, "Cannot set period size");
|
||||||
|
@@ -417,7 +417,6 @@ CurlInputStream::InitEasy()
|
|||||||
request->SetOption(CURLOPT_HTTP200ALIASES, http_200_aliases);
|
request->SetOption(CURLOPT_HTTP200ALIASES, http_200_aliases);
|
||||||
request->SetOption(CURLOPT_FOLLOWLOCATION, 1L);
|
request->SetOption(CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
request->SetOption(CURLOPT_MAXREDIRS, 5L);
|
request->SetOption(CURLOPT_MAXREDIRS, 5L);
|
||||||
request->SetOption(CURLOPT_FAILONERROR, 1L);
|
|
||||||
|
|
||||||
/* this option eliminates the probe request when
|
/* this option eliminates the probe request when
|
||||||
username/password are specified */
|
username/password are specified */
|
||||||
@@ -439,6 +438,14 @@ CurlInputStream::InitEasy()
|
|||||||
request->SetVerifyPeer(verify_peer);
|
request->SetVerifyPeer(verify_peer);
|
||||||
request->SetVerifyHost(verify_host);
|
request->SetVerifyHost(verify_host);
|
||||||
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
|
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
|
||||||
|
|
||||||
|
try {
|
||||||
|
request->SetProxyVerifyPeer(verify_peer);
|
||||||
|
request->SetProxyVerifyHost(verify_host);
|
||||||
|
} catch (...) {
|
||||||
|
/* these methods fail if libCURL was compiled with
|
||||||
|
CURL_DISABLE_PROXY; ignore silently */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -42,6 +42,8 @@
|
|||||||
#include "io/UniqueFileDescriptor.hxx"
|
#include "io/UniqueFileDescriptor.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
class Path;
|
class Path;
|
||||||
class FileInfo;
|
class FileInfo;
|
||||||
|
|
||||||
|
@@ -49,9 +49,6 @@ Java::File::Initialise(JNIEnv *env) noexcept
|
|||||||
AllocatedPath
|
AllocatedPath
|
||||||
Java::File::ToAbsolutePath(JNIEnv *env, jobject _file) noexcept
|
Java::File::ToAbsolutePath(JNIEnv *env, jobject _file) noexcept
|
||||||
{
|
{
|
||||||
assert(env != nullptr);
|
|
||||||
assert(_file != nullptr);
|
|
||||||
|
|
||||||
LocalObject file(env, _file);
|
LocalObject file(env, _file);
|
||||||
|
|
||||||
const jstring path = GetAbsolutePath(env, file);
|
const jstring path = GetAbsolutePath(env, file);
|
||||||
|
@@ -18,13 +18,13 @@ endif
|
|||||||
|
|
||||||
conf.set('HAVE_MD5', crypto_md5_dep.found())
|
conf.set('HAVE_MD5', crypto_md5_dep.found())
|
||||||
|
|
||||||
if libavutil_dep.found()
|
if ffmpeg_util_dep.found()
|
||||||
crypto_base64 = static_library(
|
crypto_base64 = static_library(
|
||||||
'crypto_base64',
|
'crypto_base64',
|
||||||
'Base64.cxx',
|
'Base64.cxx',
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
libavutil_dep,
|
ffmpeg_util_dep,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -186,10 +186,6 @@ public:
|
|||||||
SetOption(CURLOPT_POSTFIELDSIZE, (long)size);
|
SetOption(CURLOPT_POSTFIELDSIZE, (long)size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetHttpPost(const struct curl_httppost *post) {
|
|
||||||
SetOption(CURLOPT_HTTPPOST, post);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool GetInfo(CURLINFO info, T value_r) const noexcept {
|
bool GetInfo(CURLINFO info, T value_r) const noexcept {
|
||||||
return ::curl_easy_getinfo(handle, info, value_r) == CURLE_OK;
|
return ::curl_easy_getinfo(handle, info, value_r) == CURLE_OK;
|
||||||
@@ -199,10 +195,10 @@ public:
|
|||||||
* Returns the response body's size, or -1 if that is unknown.
|
* Returns the response body's size, or -1 if that is unknown.
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
int64_t GetContentLength() const noexcept {
|
curl_off_t GetContentLength() const noexcept {
|
||||||
double value;
|
curl_off_t value;
|
||||||
return GetInfo(CURLINFO_CONTENT_LENGTH_DOWNLOAD, &value)
|
return GetInfo(CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &value)
|
||||||
? (int64_t)value
|
? value
|
||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -123,6 +123,14 @@ public:
|
|||||||
easy.SetVerifyPeer(value);
|
easy.SetVerifyPeer(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetProxyVerifyHost(bool value) {
|
||||||
|
easy.SetOption(CURLOPT_PROXY_SSL_VERIFYHOST, value ? 2L : 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetProxyVerifyPeer(bool value) {
|
||||||
|
easy.SetOption(CURLOPT_PROXY_SSL_VERIFYPEER, value);
|
||||||
|
}
|
||||||
|
|
||||||
void SetNoBody(bool value=true) {
|
void SetNoBody(bool value=true) {
|
||||||
easy.SetNoBody(value);
|
easy.SetNoBody(value);
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
curl_dep = dependency('libcurl', version: '>= 7.33', required: get_option('curl'))
|
curl_dep = dependency('libcurl', version: '>= 7.55', required: get_option('curl'))
|
||||||
conf.set('ENABLE_CURL', curl_dep.found())
|
conf.set('ENABLE_CURL', curl_dep.found())
|
||||||
if not curl_dep.found()
|
if not curl_dep.found()
|
||||||
subdir_done()
|
subdir_done()
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
Index: curl-7.84.0/CMakeLists.txt
|
Index: curl-7.85.0/CMakeLists.txt
|
||||||
===================================================================
|
===================================================================
|
||||||
--- curl-7.84.0.orig/CMakeLists.txt
|
--- curl-7.85.0.orig/CMakeLists.txt
|
||||||
+++ curl-7.84.0/CMakeLists.txt
|
+++ curl-7.85.0/CMakeLists.txt
|
||||||
@@ -1536,7 +1536,7 @@ set(includedir "\${prefix}/
|
@@ -1655,7 +1655,7 @@
|
||||||
set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
||||||
set(LIBCURL_LIBS "")
|
set(LIBCURL_LIBS "")
|
||||||
set(libdir "${CMAKE_INSTALL_PREFIX}/lib")
|
set(libdir "${CMAKE_INSTALL_PREFIX}/lib")
|
||||||
-foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
|
- foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
|
||||||
+foreach(_lib ${CURL_LIBS})
|
+ foreach(_lib ${CURL_LIBS})
|
||||||
if(TARGET "${_lib}")
|
if(TARGET "${_lib}")
|
||||||
set(_libname "${_lib}")
|
set(_libname "${_lib}")
|
||||||
get_target_property(_imported "${_libname}" IMPORTED)
|
get_target_property(_imported "${_libname}" IMPORTED)
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "Iter.hxx"
|
#include "Iter.hxx"
|
||||||
#include "Values.hxx"
|
#include "Values.hxx"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace ODBus {
|
namespace ODBus {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2021 The Music Player Daemon Project
|
* Copyright 2003-2022 The Music Player Daemon Project
|
||||||
* http://www.musicpd.org
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -17,26 +17,23 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "LogError.hxx"
|
#pragma once
|
||||||
#include "Domain.hxx"
|
|
||||||
#include "Log.hxx"
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavutil/error.h>
|
#include <libavutil/samplefmt.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
#include <fmt/format.h>
|
||||||
LogFfmpegError(int errnum)
|
|
||||||
{
|
|
||||||
char msg[256];
|
|
||||||
av_strerror(errnum, msg, sizeof(msg));
|
|
||||||
LogError(ffmpeg_domain, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
template<>
|
||||||
LogFfmpegError(int errnum, const char *prefix)
|
struct fmt::formatter<AVSampleFormat> : formatter<string_view>
|
||||||
{
|
{
|
||||||
char msg[256];
|
template<typename FormatContext>
|
||||||
av_strerror(errnum, msg, sizeof(msg));
|
auto format(const AVSampleFormat format, FormatContext &ctx) const {
|
||||||
FmtError(ffmpeg_domain, "{}: {}", prefix, msg);
|
const char *name = av_get_sample_fmt_name(format);
|
||||||
}
|
if (name == nullptr)
|
||||||
|
name = "?";
|
||||||
|
|
||||||
|
return formatter<string_view>::format(name, ctx);
|
||||||
|
}
|
||||||
|
};
|
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2003-2021 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 MPD_FFMPEG_LOG_ERROR_HXX
|
|
||||||
#define MPD_FFMPEG_LOG_ERROR_HXX
|
|
||||||
|
|
||||||
void
|
|
||||||
LogFfmpegError(int errnum);
|
|
||||||
|
|
||||||
void
|
|
||||||
LogFfmpegError(int errnum, const char *prefix);
|
|
||||||
|
|
||||||
#endif
|
|
@@ -13,6 +13,29 @@ else
|
|||||||
endif
|
endif
|
||||||
conf.set('HAVE_LIBAVFILTER', libavfilter_dep.found())
|
conf.set('HAVE_LIBAVFILTER', libavfilter_dep.found())
|
||||||
|
|
||||||
|
if not libavutil_dep.found()
|
||||||
|
ffmpeg_util_dep = dependency('', required: false)
|
||||||
|
ffmpeg_dep = dependency('', required: false)
|
||||||
|
subdir_done()
|
||||||
|
endif
|
||||||
|
|
||||||
|
ffmpeg_util = static_library(
|
||||||
|
'ffmpeg_util',
|
||||||
|
'Interleave.cxx',
|
||||||
|
'Error.cxx',
|
||||||
|
include_directories: inc,
|
||||||
|
dependencies: [
|
||||||
|
libavutil_dep,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
ffmpeg_util_dep = declare_dependency(
|
||||||
|
link_with: ffmpeg_util,
|
||||||
|
dependencies: [
|
||||||
|
libavutil_dep,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
if not enable_ffmpeg
|
if not enable_ffmpeg
|
||||||
ffmpeg_dep = dependency('', required: false)
|
ffmpeg_dep = dependency('', required: false)
|
||||||
subdir_done()
|
subdir_done()
|
||||||
@@ -30,17 +53,16 @@ ffmpeg = static_library(
|
|||||||
'ffmpeg',
|
'ffmpeg',
|
||||||
'Init.cxx',
|
'Init.cxx',
|
||||||
'Interleave.cxx',
|
'Interleave.cxx',
|
||||||
'LogError.cxx',
|
|
||||||
'LogCallback.cxx',
|
'LogCallback.cxx',
|
||||||
'Error.cxx',
|
'Error.cxx',
|
||||||
'Domain.cxx',
|
'Domain.cxx',
|
||||||
ffmpeg_sources,
|
ffmpeg_sources,
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
ffmpeg_util_dep,
|
||||||
libavformat_dep,
|
libavformat_dep,
|
||||||
libavcodec_dep,
|
libavcodec_dep,
|
||||||
libavfilter_dep,
|
libavfilter_dep,
|
||||||
libavutil_dep,
|
|
||||||
log_dep,
|
log_dep,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -48,9 +70,9 @@ ffmpeg = static_library(
|
|||||||
ffmpeg_dep = declare_dependency(
|
ffmpeg_dep = declare_dependency(
|
||||||
link_with: ffmpeg,
|
link_with: ffmpeg,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
ffmpeg_util_dep,
|
||||||
libavformat_dep,
|
libavformat_dep,
|
||||||
libavcodec_dep,
|
libavcodec_dep,
|
||||||
libavfilter_dep,
|
libavfilter_dep,
|
||||||
libavutil_dep,
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@@ -39,7 +39,7 @@ template<>
|
|||||||
struct fmt::formatter<SampleFormat> : formatter<string_view>
|
struct fmt::formatter<SampleFormat> : formatter<string_view>
|
||||||
{
|
{
|
||||||
template<typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(const SampleFormat format, FormatContext &ctx) {
|
auto format(const SampleFormat format, FormatContext &ctx) const {
|
||||||
return formatter<string_view>::format(sample_format_to_string(format),
|
return formatter<string_view>::format(sample_format_to_string(format),
|
||||||
ctx);
|
ctx);
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ template<>
|
|||||||
struct fmt::formatter<AudioFormat> : formatter<string_view>
|
struct fmt::formatter<AudioFormat> : formatter<string_view>
|
||||||
{
|
{
|
||||||
template<typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(const AudioFormat &af, FormatContext &ctx) {
|
auto format(const AudioFormat &af, FormatContext &ctx) const {
|
||||||
return formatter<string_view>::format(ToString(af).c_str(),
|
return formatter<string_view>::format(ToString(af).c_str(),
|
||||||
ctx);
|
ctx);
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,7 @@ template<>
|
|||||||
struct fmt::formatter<std::exception_ptr> : formatter<string_view>
|
struct fmt::formatter<std::exception_ptr> : formatter<string_view>
|
||||||
{
|
{
|
||||||
template<typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(std::exception_ptr e, FormatContext &ctx) {
|
auto format(std::exception_ptr e, FormatContext &ctx) const {
|
||||||
return formatter<string_view>::format(GetFullMessage(e), ctx);
|
return formatter<string_view>::format(GetFullMessage(e), ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -29,7 +29,7 @@ template<>
|
|||||||
struct fmt::formatter<Path> : formatter<string_view>
|
struct fmt::formatter<Path> : formatter<string_view>
|
||||||
{
|
{
|
||||||
template<typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(Path path, FormatContext &ctx) {
|
auto format(Path path, FormatContext &ctx) const {
|
||||||
return formatter<string_view>::format(path.ToUTF8(), ctx);
|
return formatter<string_view>::format(path.ToUTF8(), ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
icu_dep = dependency('icu-i18n', version: '>= 50', required: get_option('icu'))
|
icu_i18n_dep = dependency('icu-i18n', version: '>= 50', required: get_option('icu'))
|
||||||
conf.set('HAVE_ICU', icu_dep.found())
|
icu_uc_dep = dependency('icu-uc', version: '>= 50', required: get_option('icu'))
|
||||||
|
have_icu = icu_i18n_dep.found() and icu_uc_dep.found()
|
||||||
|
conf.set('HAVE_ICU', have_icu)
|
||||||
|
|
||||||
icu_sources = [
|
icu_sources = [
|
||||||
'CaseFold.cxx',
|
'CaseFold.cxx',
|
||||||
@@ -13,7 +15,7 @@ if is_windows
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
iconv_dep = []
|
iconv_dep = []
|
||||||
if icu_dep.found()
|
if have_icu
|
||||||
icu_sources += [
|
icu_sources += [
|
||||||
'Util.cxx',
|
'Util.cxx',
|
||||||
'Init.cxx',
|
'Init.cxx',
|
||||||
@@ -44,7 +46,8 @@ icu = static_library(
|
|||||||
icu_sources,
|
icu_sources,
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
icu_dep,
|
icu_i18n_dep,
|
||||||
|
icu_uc_dep,
|
||||||
iconv_dep,
|
iconv_dep,
|
||||||
fmt_dep,
|
fmt_dep,
|
||||||
],
|
],
|
||||||
|
22
src/lib/modplug/patches/no_register
Normal file
22
src/lib/modplug/patches/no_register
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Index: libmodplug-0.8.9.0/src/fastmix.cpp
|
||||||
|
===================================================================
|
||||||
|
--- libmodplug-0.8.9.0.orig/src/fastmix.cpp
|
||||||
|
+++ libmodplug-0.8.9.0/src/fastmix.cpp
|
||||||
|
@@ -288,7 +288,7 @@ CzWINDOWEDFIR sfir;
|
||||||
|
// MIXING MACROS
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
#define SNDMIX_BEGINSAMPLELOOP8\
|
||||||
|
- register MODCHANNEL * const pChn = pChannel;\
|
||||||
|
+ MODCHANNEL * const pChn = pChannel;\
|
||||||
|
nPos = pChn->nPosLo;\
|
||||||
|
const signed char *p = (signed char *)(pChn->pCurrentSample+pChn->nPos);\
|
||||||
|
if (pChn->dwFlags & CHN_STEREO) p += pChn->nPos;\
|
||||||
|
@@ -296,7 +296,7 @@ CzWINDOWEDFIR sfir;
|
||||||
|
do {
|
||||||
|
|
||||||
|
#define SNDMIX_BEGINSAMPLELOOP16\
|
||||||
|
- register MODCHANNEL * const pChn = pChannel;\
|
||||||
|
+ MODCHANNEL * const pChn = pChannel;\
|
||||||
|
nPos = pChn->nPosLo;\
|
||||||
|
const signed short *p = (signed short *)(pChn->pCurrentSample+(pChn->nPos*2));\
|
||||||
|
if (pChn->dwFlags & CHN_STEREO) p += pChn->nPos;\
|
1
src/lib/modplug/patches/series
Normal file
1
src/lib/modplug/patches/series
Normal file
@@ -0,0 +1 @@
|
|||||||
|
no_register
|
@@ -812,8 +812,12 @@ AlsaOutput::Open(AudioFormat &audio_format)
|
|||||||
fmt::format("Failed to open ALSA device \"{}\"",
|
fmt::format("Failed to open ALSA device \"{}\"",
|
||||||
GetDevice()).c_str());
|
GetDevice()).c_str());
|
||||||
|
|
||||||
|
const char *pcm_name = snd_pcm_name(pcm);
|
||||||
|
if (pcm_name == nullptr)
|
||||||
|
pcm_name = "?";
|
||||||
|
|
||||||
FmtDebug(alsa_output_domain, "opened {} type={}",
|
FmtDebug(alsa_output_domain, "opened {} type={}",
|
||||||
snd_pcm_name(pcm),
|
pcm_name,
|
||||||
snd_pcm_type_name(snd_pcm_type(pcm)));
|
snd_pcm_type_name(snd_pcm_type(pcm)));
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
|
@@ -627,7 +627,7 @@ osx_render(void *vdata,
|
|||||||
{
|
{
|
||||||
OSXOutput *od = (OSXOutput *) vdata;
|
OSXOutput *od = (OSXOutput *) vdata;
|
||||||
|
|
||||||
int count = in_number_frames * od->asbd.mBytesPerFrame;
|
std::size_t count = in_number_frames * od->asbd.mBytesPerFrame;
|
||||||
buffer_list->mBuffers[0].mDataByteSize =
|
buffer_list->mBuffers[0].mDataByteSize =
|
||||||
od->ring_buffer->pop((uint8_t *)buffer_list->mBuffers[0].mData,
|
od->ring_buffer->pop((uint8_t *)buffer_list->mBuffers[0].mData,
|
||||||
count);
|
count);
|
||||||
|
@@ -523,7 +523,13 @@ PipeWireOutput::Open(AudioFormat &audio_format)
|
|||||||
pw_properties_setf(props, PW_KEY_REMOTE_NAME, "%s", remote);
|
pw_properties_setf(props, PW_KEY_REMOTE_NAME, "%s", remote);
|
||||||
|
|
||||||
if (target != nullptr && target_id == PW_ID_ANY)
|
if (target != nullptr && target_id == PW_ID_ANY)
|
||||||
pw_properties_setf(props, PW_KEY_NODE_TARGET, "%s", target);
|
pw_properties_setf(props,
|
||||||
|
#if PW_CHECK_VERSION(0, 3, 64)
|
||||||
|
PW_KEY_TARGET_OBJECT,
|
||||||
|
#else
|
||||||
|
PW_KEY_NODE_TARGET,
|
||||||
|
#endif
|
||||||
|
"%s", target);
|
||||||
|
|
||||||
#ifdef PW_KEY_NODE_RATE
|
#ifdef PW_KEY_NODE_RATE
|
||||||
/* ask PipeWire to change the graph sample rate to ours
|
/* ask PipeWire to change the graph sample rate to ours
|
||||||
@@ -967,6 +973,8 @@ PipeWireOutput::SendTag(const Tag &tag)
|
|||||||
|
|
||||||
struct spa_dict dict = SPA_DICT_INIT(items, n_items);
|
struct spa_dict dict = SPA_DICT_INIT(items, n_items);
|
||||||
|
|
||||||
|
const PipeWire::ThreadLoopLock lock(thread_loop);
|
||||||
|
|
||||||
auto rc = pw_stream_update_properties(stream, &dict);
|
auto rc = pw_stream_update_properties(stream, &dict);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
LogWarning(pipewire_output_domain, "Error updating properties");
|
LogWarning(pipewire_output_domain, "Error updating properties");
|
||||||
|
@@ -1026,7 +1026,7 @@ WasapiOutput::EnumerateDevices(IMMDeviceEnumerator &enumerator)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
FmtNotice(wasapi_output_domain,
|
FmtNotice(wasapi_output_domain,
|
||||||
"Device \"{}\" \"{}\"", i, name);
|
"Device \"{}\" \"{}\"", i, name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,7 +17,6 @@ storage_glue = static_library(
|
|||||||
'CompositeStorage.cxx',
|
'CompositeStorage.cxx',
|
||||||
'MemoryDirectoryReader.cxx',
|
'MemoryDirectoryReader.cxx',
|
||||||
'Configured.cxx',
|
'Configured.cxx',
|
||||||
'StorageState.cxx',
|
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
boost_dep,
|
boost_dep,
|
||||||
@@ -31,4 +30,3 @@ storage_glue_dep = declare_dependency(
|
|||||||
storage_plugins_dep,
|
storage_plugins_dep,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
#include "storage/StorageInterface.hxx"
|
#include "storage/StorageInterface.hxx"
|
||||||
#include "storage/FileInfo.hxx"
|
#include "storage/FileInfo.hxx"
|
||||||
#include "storage/MemoryDirectoryReader.hxx"
|
#include "storage/MemoryDirectoryReader.hxx"
|
||||||
|
#include "lib/curl/Error.hxx"
|
||||||
#include "lib/curl/Init.hxx"
|
#include "lib/curl/Init.hxx"
|
||||||
#include "lib/curl/Global.hxx"
|
#include "lib/curl/Global.hxx"
|
||||||
#include "lib/curl/Slist.hxx"
|
#include "lib/curl/Slist.hxx"
|
||||||
@@ -34,7 +35,6 @@
|
|||||||
#include "event/InjectEvent.hxx"
|
#include "event/InjectEvent.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "time/Parser.hxx"
|
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
@@ -171,8 +171,9 @@ struct DavResponse {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
static unsigned
|
static unsigned
|
||||||
ParseStatus(const char *s)
|
ParseStatus(const char *s) noexcept
|
||||||
{
|
{
|
||||||
/* skip the "HTTP/1.1" prefix */
|
/* skip the "HTTP/1.1" prefix */
|
||||||
const char *space = std::strchr(s, ' ');
|
const char *space = std::strchr(s, ' ');
|
||||||
@@ -182,37 +183,37 @@ ParseStatus(const char *s)
|
|||||||
return strtoul(space + 1, nullptr, 10);
|
return strtoul(space + 1, nullptr, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
static unsigned
|
static unsigned
|
||||||
ParseStatus(const char *s, size_t length)
|
ParseStatus(const char *s, size_t length) noexcept
|
||||||
{
|
{
|
||||||
return ParseStatus(std::string(s, length).c_str());
|
return ParseStatus(std::string(s, length).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
static std::chrono::system_clock::time_point
|
static std::chrono::system_clock::time_point
|
||||||
ParseTimeStamp(const char *s)
|
ParseTimeStamp(const char *s) noexcept
|
||||||
{
|
{
|
||||||
try {
|
return std::chrono::system_clock::from_time_t(curl_getdate(s, nullptr));
|
||||||
// TODO: make this more robust
|
|
||||||
return ParseTimePoint(s, "%a, %d %b %Y %T");
|
|
||||||
} catch (...) {
|
|
||||||
return std::chrono::system_clock::time_point::min();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
static std::chrono::system_clock::time_point
|
static std::chrono::system_clock::time_point
|
||||||
ParseTimeStamp(const char *s, size_t length)
|
ParseTimeStamp(const char *s, size_t length) noexcept
|
||||||
{
|
{
|
||||||
return ParseTimeStamp(std::string(s, length).c_str());
|
return ParseTimeStamp(std::string(s, length).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
static uint64_t
|
static uint64_t
|
||||||
ParseU64(const char *s)
|
ParseU64(const char *s) noexcept
|
||||||
{
|
{
|
||||||
return strtoull(s, nullptr, 10);
|
return strtoull(s, nullptr, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
static uint64_t
|
static uint64_t
|
||||||
ParseU64(const char *s, size_t length)
|
ParseU64(const char *s, size_t length) noexcept
|
||||||
{
|
{
|
||||||
return ParseU64(std::string(s, length).c_str());
|
return ParseU64(std::string(s, length).c_str());
|
||||||
}
|
}
|
||||||
@@ -278,6 +279,7 @@ public:
|
|||||||
"<a:resourcetype/>"
|
"<a:resourcetype/>"
|
||||||
"<a:getcontenttype/>"
|
"<a:getcontenttype/>"
|
||||||
"<a:getcontentlength/>"
|
"<a:getcontentlength/>"
|
||||||
|
"<a:getlastmodified/>"
|
||||||
"</a:prop>"
|
"</a:prop>"
|
||||||
"</a:propfind>");
|
"</a:propfind>");
|
||||||
}
|
}
|
||||||
@@ -299,8 +301,9 @@ private:
|
|||||||
/* virtual methods from CurlResponseHandler */
|
/* virtual methods from CurlResponseHandler */
|
||||||
void OnHeaders(unsigned status, Curl::Headers &&headers) final {
|
void OnHeaders(unsigned status, Curl::Headers &&headers) final {
|
||||||
if (status != 207)
|
if (status != 207)
|
||||||
throw FormatRuntimeError("Status %d from WebDAV server; expected \"207 Multi-Status\"",
|
throw HttpStatusError(status,
|
||||||
status);
|
StringFormat<80>("Status %u from WebDAV server; expected \"207 Multi-Status\"",
|
||||||
|
status).c_str());
|
||||||
|
|
||||||
if (!IsXmlContentType(headers))
|
if (!IsXmlContentType(headers))
|
||||||
throw std::runtime_error("Unexpected Content-Type from WebDAV server");
|
throw std::runtime_error("Unexpected Content-Type from WebDAV server");
|
||||||
|
@@ -70,8 +70,11 @@ FormatLastError(DWORD code, const char *fmt, Args&&... args) noexcept
|
|||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
const auto end = buffer + sizeof(buffer);
|
const auto end = buffer + sizeof(buffer);
|
||||||
size_t length = snprintf(buffer, sizeof(buffer) - 128,
|
constexpr std::size_t max_prefix = sizeof(buffer) - 128;
|
||||||
|
size_t length = snprintf(buffer, max_prefix,
|
||||||
fmt, std::forward<Args>(args)...);
|
fmt, std::forward<Args>(args)...);
|
||||||
|
if (length >= max_prefix)
|
||||||
|
length = max_prefix - 1;
|
||||||
char *p = buffer + length;
|
char *p = buffer + length;
|
||||||
*p++ = ':';
|
*p++ = ':';
|
||||||
*p++ = ' ';
|
*p++ = ' ';
|
||||||
|
@@ -263,8 +263,14 @@ TagBuilder::RemoveAll() noexcept
|
|||||||
void
|
void
|
||||||
TagBuilder::RemoveType(TagType type) noexcept
|
TagBuilder::RemoveType(TagType type) noexcept
|
||||||
{
|
{
|
||||||
|
if (items.empty())
|
||||||
|
/* don't acquire the tag_pool_lock if we're not going
|
||||||
|
to call tag_pool_put_item() anyway */
|
||||||
|
return;
|
||||||
|
|
||||||
const auto begin = items.begin(), end = items.end();
|
const auto begin = items.begin(), end = items.end();
|
||||||
|
|
||||||
|
const std::scoped_lock<Mutex> protect(tag_pool_lock);
|
||||||
items.erase(std::remove_if(begin, end,
|
items.erase(std::remove_if(begin, end,
|
||||||
[type](TagItem *item) {
|
[type](TagItem *item) {
|
||||||
if (item->type != type)
|
if (item->type != type)
|
||||||
|
@@ -26,6 +26,11 @@
|
|||||||
|
|
||||||
class TagMask {
|
class TagMask {
|
||||||
typedef uint_least32_t mask_t;
|
typedef uint_least32_t mask_t;
|
||||||
|
|
||||||
|
/* the mask must have enough bits to represent all tags
|
||||||
|
supported by MPD */
|
||||||
|
static_assert(TAG_NUM_OF_ITEM_TYPES <= sizeof(mask_t) * 8);
|
||||||
|
|
||||||
mask_t value;
|
mask_t value;
|
||||||
|
|
||||||
explicit constexpr TagMask(uint_least32_t _value) noexcept
|
explicit constexpr TagMask(uint_least32_t _value) noexcept
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user