Compare commits

...

1204 Commits

Author SHA1 Message Date
8842650c33 release v0.23.13 2023-05-22 19:46:38 +02:00
d5bf128cee storage/curl: throw HttpStatusError 2023-05-22 19:29:46 +02:00
5cd86e272f input/curl: disable CURLOPT_FAILONERROR
Let OnHeaders() check the status.

The status checking code was added by commit 4f021cbced in 2011,
but in 2008, commit a8e81326d0 enabled `CURLOPT_FAILONERROR`, which
means the status checking code never had any effect.

This allows `LoadExcludeListOrLog()` to hide boring "404 Not Found"
log messages via `IsFileNotFound()`.
2023-05-22 19:03:12 +02:00
740cbe9e02 event/Loop: remove failing assert()
The `assert(!quit)` can fail if the `EventThread` gets stopped before
it enters `EventLoop::Run()`. There is a similar problem with `alive`,
which gets reset by `EventThread::Stop()`.

If that happens, then `EventLoop::Run()` should return immediately
without handling any events.
2023-05-22 18:14:25 +02:00
ed890a273a doc/user.rst: document the replaygain_missing_preamp setting
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1785
2023-05-22 16:17:05 +02:00
068cd559e1 db/update/Walk: clear Song::in_playlist
Without clearing all `in_playlist` flags, the songs will never be
revealed again if they were hidden once by a CUE sheet, not even after
the CUE sheet gets deleted or modified.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1784
2023-05-22 15:41:58 +02:00
dc127f39a7 util/ScopeExit: use std::declval()
Fixes GCC 10 error:

 error: cannot call member function `Foo` without object
2023-05-22 15:01:25 +02:00
7a99a7008c util/ScopeExit: use std::exchange() 2023-05-22 14:44:45 +02:00
70b451db7b util/ScopeExit: add noexcept 2023-05-22 14:44:17 +02:00
2ab03a0914 util/ScopeExit: allow the function to throw
Fixes crash inside AtScopeExit() in the WASAPI output plugin.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1759
2023-05-22 14:43:23 +02:00
2fa8c7d2db lib/crypto/meson.build: link with ffmpeg_util_dep
This adds `MakeFfmpegError()` to the executable and fixes a linker
failure when `libavutil` is available, but `libavformat` and
`libavcodec` are not.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1786
2023-05-22 14:05:13 +02:00
7c759ba8b0 lib/ffmpeg/meson.build: move libavutil helpers into separate library 2023-05-22 14:03:47 +02:00
6d9b452fde lib/ffmpeg/LogError: remove unused library 2023-05-22 13:48:33 +02:00
f7eb1c9a83 Fix meson build warning for get_pkgconfig_variable
Otherwise, building will generate these warnings:

systemd/system/meson.build:5: WARNING: Project targeting '>= 0.56.0' but tried to use feature deprecated since '0.56.0': Dependency.get_pkgconfig_variable. use Dependency.get_variable(pkgconfig : ...) instead
systemd/user/meson.build:5: WARNING: Project targeting '>= 0.56.0' but tried to use feature deprecated since '0.56.0': Dependency.get_pkgconfig_variable. use Dependency.get_variable(pkgconfig : ...) instead
2023-05-21 21:07:14 +02:00
2d22e6dee4 subprojects: update sqlite to 3.41.2-2 2023-05-21 21:05:17 +02:00
4587bf759d subprojects: update expat to 2.5.0-2 2023-05-21 21:04:56 +02:00
e1e37cfe3c TagPrint, command/File: two more libfmt 10 workarounds
libfmt 10 doesn't know how to format a StringView, and doesn't cast to
std::string_view anymore.  The StringView class has been removed from
MPD 0.24 completely, and this is a stable-branch-only workaround.

Closes https://github.com/MusicPlayerDaemon/MPD/pull/1814
2023-05-21 21:03:20 +02:00
381934985a reorder ffmpeg to be lower priority than gme
This should prevent ffmpeg from taking priority over the gme plugin.
The ffmpeg plugin is more buggy than gme.
One of the prominent bugs of preferring ffmpeg over gme is that ffmpeg
cannot seek SAP files while gme can. This should prevent that from
happening.
2023-05-21 20:58:53 +02:00
a8042885ac TimePrint: minor fixup for libfmt 10
libfmt version 10 has difficulties formatting a `StringBuffer`, and we
need to help it by explicitly invoking the `c_str()` method.
2023-05-21 20:58:19 +02:00
a71e68db50 command/player, SongPrint: use AudioFormatFormatter()
libfmt version 10 apparently doesn't know how to format a
`StringBuffer`, failing the MPD build.  Since we have a formatter
specialization for `AudioFormat`, let's use that - it's better and
easier to use.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1807
2023-05-21 20:57:59 +02:00
1417578b3d db/update/Archive: validate directory names
Fixes assertion failure if the ZIP file contains a path that begins
with a slash.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1793
2023-05-21 20:57:38 +02:00
96befa138c db/update/Archive: ignore filenames with newline character 2023-05-21 20:56:38 +02:00
16a99804de db/update/Archive: move check to IsAcceptableFilename() 2023-05-21 20:56:32 +02:00
75a39ed279 db/update/Archive: remove useless log message 2023-05-21 20:55:59 +02:00
4d357ab77c Fix syntax error in mpdconf.example 2023-05-21 20:51:57 +02:00
d4f3dd49b4 db/SimpleDatabasePlugin: store in_playlist value of songs into database
Fixes hide_playlist_targets not working after server restart

Currently, `hide_playlists_targets` works by skipping songs with
`in_playlist` value set to true in
[`Directory::Walk`](a57bcd0238/src/db/plugins/simple/Directory.cxx (L237)). But
`in_playlist` is not stored and only updated in
[`UpdateWalk::PurgeDanglingFromPlaylists`](a57bcd0238/src/db/update/Playlist.cxx (L139)),
which will only be executed while updating DB.

This causes the problem that playlist target songs are correctly
hidden after database update, but will remain visible after mpd server
restarted. This pr solves the problem by storing `in_playlist` value
of songs into the `SimpleDatabase` file.
2023-05-21 20:51:47 +02:00
4ec6d0555a check systemd unit dir from systemd.pc in meson 2023-05-21 20:51:33 +02:00
a6a1182c4c python/build/libs.py: update OpenSSL to 3.1.0 2023-05-21 20:50:03 +02:00
a59c9c602b python/build/libs.py: update CURL to 8.0.1 2023-05-21 20:50:03 +02:00
0c4d824d64 subprojects/sqlite3.wrap: update to 3.41.0-1 2023-05-21 20:50:03 +02:00
a5281856c9 python/build/libs.py: update WildMidi to 0.4.5 2023-05-21 20:50:03 +02:00
0206a46d39 decoder/gme: require GME 0.6 or later
This allows dropping a few compile-time version checks and we can use
pkg-config to detect the library.
2023-05-21 20:50:03 +02:00
9475ef2202 fs/Charset: assign fs_charset
This got lost 8 years ago in commit 87c88fcb27

D'oh!
2023-05-21 20:50:03 +02:00
edae00e719 fs/Charset: remove useless log message 2023-05-21 20:50:03 +02:00
fb695bc55f command/{file,storage}: remove stray "#pragma GCC diagnostic pop" 2023-05-21 20:50:03 +02:00
23a5b8fd3c python/build/meson.py: remove unused import 2023-05-21 20:43:09 +02:00
273a93cfcf build/python/cmake: set CMAKE_C_FLAGS_INIT, not CMAKE_C_FLAGS
According to
https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_INIT.html
the _INIT variables should be set in the toolchain file.
2023-05-21 20:43:05 +02:00
d105985d78 build/python/cmake: set CMAKE_OSX_SYSROOT on macOS 2023-05-21 20:43:00 +02:00
f8cfeb39e9 build/python/cmake: add "env" parameter 2023-05-21 20:42:51 +02:00
d5d3982d3c build/python/build/project.py: add "lazy" parameter to make_build_path() 2023-05-21 20:42:27 +02:00
47341107ea build/python/build/project.py: raise exception on regex mismatch 2023-05-21 20:42:18 +02:00
90eaa87a4d python/build/zlib.py: use autotools to be more portable
Right now, zlib is only built for Windows, but we may eventually
changed that, so don't hard-code `win32/Makefile.gcc`.
2023-05-21 20:42:12 +02:00
b09a54b2c2 python/build/autotools.py: use toolchain.arflags 2023-05-21 20:42:04 +02:00
10aec174d5 python/{cmake,autotools}: build in verbose mode
Make sure all the gory details are visible in CI logs.
2023-05-21 20:41:49 +02:00
d32ed194e8 python/build/autotools.py: dump config.log on configure error
For better error logs on CI.
2023-05-21 20:41:44 +02:00
70d0fbd715 python/makeproject: do not use hard-code absolute path to make 2023-05-21 20:41:38 +02:00
302432e157 python/makeproject: set appropriate build jobs count depending on the number of CPUs 2023-05-21 20:41:34 +02:00
4ab8a677dc build/python: do not use absolute path for tar 2023-05-21 20:41:29 +02:00
52e4a4c904 build/python/build/project.py: lazy tarball extraction 2023-05-21 20:41:25 +02:00
a0f6932ebe unix/SignalHandlers: shut down if parent process dies in --no-daemon mode
By default, if the parent of a process dies, the process gets SIGHUP
and is supposed to shut down.  This however doesn't work for MPD,
because MPD redefines SIGHUP with a different meaning (like most
daemons do).

To work around this, we configure the kernel to send SIGTERM instead
of SIGHUP.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1706
2023-05-21 20:40:47 +02:00
6e700dab69 CommandLine: hard-code daemon=false if ENABLE_DAEMON is not set 2023-05-21 20:40:39 +02:00
35eaed7206 python/build/libs.py: update FFmpeg to 6.0 2023-05-21 20:40:39 +02:00
e7c963f2ce python/build/libs.py: disable more unused FFmpeg features 2023-05-21 20:40:39 +02:00
949d72e368 output/PipeWire: lock thread loop in SendTag 2023-05-21 20:40:29 +02:00
8d2a184658 python/build/libs.py: update CURL to 7.88.1 2023-05-21 20:36:28 +02:00
c877a32d97 python/build/libs.py: update OpenSSL to 3.0.8 2023-05-21 20:36:23 +02:00
541468f0ca input/async: check for errors in Seek()
Fixes a busy loop in BufferingInputStream::RunThreadLocked() because
the method never learns that seeking is ignored, even though the HTTP
stream is already broken and can never be read; nobody cared to check
for errors.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1727
2023-05-21 20:34:19 +02:00
d2797effa3 command/database: add missing include for UINT_MAX 2023-05-21 20:33:34 +02:00
1170fb1e1e output/osx: change type to std::size_t to fix -Wc++11-narrowing 2023-05-21 20:33:03 +02:00
65b9b3195c lib/dbus/AppendIter: add missing include 2023-05-21 20:33:03 +02:00
258830e913 increment version number to 0.23.13 2023-05-21 20:29:23 +02:00
d91da96798 release v0.23.12 2023-01-17 18:54:47 +01:00
b3897df682 decoder/mad: add assert() 2023-01-17 18:53:18 +01:00
3cacb56bb7 fs/StandardDirectory: don't fall back to getpwuid() without $HOME
If the environment variable $HOME does not exist, don't attempt to
obtain it from /etc/passwd; without $HOME, the calling process
indicates that it does not wish MPD to access the home directory.

This also prevents MPD from attempting to load
`/root/.config/mpd/mpd.conf` if MPD got started as global systemd
service.  Reading from there makes no sense, only /etc/mpd.conf shall
be used then.

This piece of code was initially added by commit 5d85792178.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1687
2023-01-17 18:51:49 +01:00
15a1973e28 decoder/mad: fix integer underflow with very small files
When drop_start_samples and drop_end_samples overlap and are greater
than the actual number of samples, the `num_samples` calculation in
SubmitPCM() could underflow.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1712
2023-01-17 17:41:37 +01:00
ad7d47a8ba output/PipeWire: use PW_KEY_TARGET_OBJECT with PipeWire 0.3.64
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1721
2023-01-17 11:50:09 +01:00
0948c607b6 lib/curl/meson.build: require CURL 7.55.0 or later
For CURLINFO_CONTENT_LENGTH_DOWNLOAD_T (commit 4efd0a9f77).
2023-01-16 19:42:48 +01:00
60d04052c5 NEWS: mention the GCC13 fixes 2023-01-16 19:41:37 +01:00
c1780ac657 python/build/libs.py: update CURL to 7.87.0 2023-01-16 19:06:08 +01:00
e49cf0ec38 python/build/libs.py: update Boost to 1.81.0 2023-01-16 19:03:50 +01:00
e1d641f684 lib/curl/Easy: drop deprecated CURLOPT_HTTPPOST wrapper 2023-01-02 14:29:17 +01:00
4efd0a9f77 lib/curl/Easy: use CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
CURLINFO_CONTENT_LENGTH_DOWNLOAD is deprecated and is ugly because it
uses floating point.
2023-01-02 14:28:42 +01:00
f6f8751332 io/FileReader: add missing include for uint64_t 2023-01-02 14:27:47 +01:00
gd
abb28593ce TagBuilder::RemoveType: added missing tag pool lock before call to tag_pool_put_item 2022-12-29 08:43:10 +01:00
115693b046 increment version number to 0.23.12 2022-12-29 08:42:02 +01:00
e4b055eb6d v0.23.x: RemoteTagCache: add missing include
Fix build with Boost 1.81.0. `<array>` was included by one of those boost headers,
however, it's no longer included as of Boost 1.81.0.

`master` doesn't use `std::array` in this file.

While we're at it, add all necessary inclusion files.
2022-12-01 08:29:23 +07:00
9866adff95 release v0.23.11 2022-11-28 16:55:46 +01:00
a8b0c55818 input/curl: make proxy verify setting optional
These settings do not work if CURL was compiled with
CURL_DISABLE_PROXY, and cause error "An unknown option was passed in
to libcurl".

Fixes regression by commit 7ab0dfc8ce
2022-11-28 16:14:01 +01:00
cac88e8be5 python/build/libs.py: re-enable verbose error strings
This compile-time option is not about debug logging, but about
curl_easy_strerror().

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1670
2022-11-28 16:12:17 +01:00
e9f6a3482c db/Configured: add default "cache_directory" setting 2022-11-28 14:24:52 +01:00
5d2e80f188 db/Configured: use GetAppCacheDir() instead of GetUserCacheDir() 2022-11-28 14:20:15 +01:00
cfd4d5b13e StateFileConfig: use GetAppCacheDir() instead of GetUserCacheDir() 2022-11-28 14:20:14 +01:00
06514aec63 fs/StandardDirectory: add GetAppCacheDir() 2022-11-28 14:19:30 +01:00
4ded1ae67b fs/FileSystem: add CreateDirectoryNoThrow() 2022-11-28 14:19:08 +01:00
1da974e3fa fs/StandardDirectory: use PACKAGE_NAME from version.h 2022-11-28 14:05:34 +01:00
94f06f0946 fs/StandardDirectory: use mode=0777 in mkdir() call
Of course, mode=0700 is more secure, but allowing other users access
to new directories is a choice the user should make via umask().  If
the user-chosen umask allows everybody access, MPD should probably
respect that.
2022-11-28 14:04:47 +01:00
d9eec8a455 fs/StandardDirectory: do not use $RUNTIME_DIRECTORY on Android
This is systemd specific, and Android doesn't have systemd.
2022-11-28 10:44:50 +01:00
eaecbcafb2 PlaylistFile: disallow backslash in playlist names on Windows
The function spl_valid_name() should verify playlist names and prevent
path traversal, but it failed to do so on Windows, because it forgot
to check for backslashes.

This buggy piece of code was already present when stored playlists
were initially implemented in 2006 by commit 08003904d7, and
even during the many rounds of code refactoring, nobody ever bothered
to verify it.  D'oh!

(Thanks, Paul Arzelier)
2022-11-28 09:53:49 +01:00
73b5d0a9b9 system/Error: truncate the snprintf() return value
snprintf() does not return the (truncated) length actually written,
but the length that would be needed if the buffer were large enough.
This API usage mistake in FormatLastError() can lead to overflow of
the stack buffer, crashing the process (Windows only).

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1676
2022-11-28 09:42:37 +01:00
c2d0f35e7a storage/meson.build: move StorageState.cxx to "mpd" executable
Fixes spurious linker errors.
2022-11-12 12:24:48 +01:00
ab99a57997 test/meson.build: reduce test_translate_song. dependencies 2022-11-12 12:17:35 +01:00
c8ebaf3521 python/build/meson.py: use "meson setup" instead of the deprecated syntax 2022-11-12 12:10:06 +01:00
52d00f7e30 subprojects: update fmt to 9.1.0 2022-11-11 19:22:39 +01:00
309491a6d8 subprojects: update expat to 2.5.0 2022-11-11 19:22:30 +01:00
gd
e7bfd32ccc doc/index.rst: added man pages links to suppress warnings: document isn't included in any toctree 2022-11-08 14:32:40 +01:00
gd
6f283b52ab doc/conf.py: set language = 'en' to suppress warning: Invalid configuration value found 2022-11-08 14:32:32 +01:00
32bddfabea archive/plugins/meson.build: do not generate empty library
If no archive library was found, return from the "plugins" directory
without creating "libarchive_plugins.a".  Empty static libraries are
unsupported on some operating systems such as macOS.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1650
2022-11-03 20:36:00 +01:00
1944c826bc doc/conf.py: fix version regular expression
Commit 44ef34db88 was broken.
2022-11-03 20:33:08 +01:00
619bb60b26 python/build/libs.py: update FLAC to 1.4.2 2022-11-03 10:28:13 +01:00
c549e16ed1 python/build/libs.py: update CURL to 7.86.0 2022-11-03 10:28:13 +01:00
01c9c4507f python/build/libs.py: update OpenSSL to 3.0.7
Punycode hooray!
2022-11-03 10:28:13 +01:00
8c9d7bf07e increment version number to 0.23.11 2022-10-20 19:09:03 +02:00
44ef34db88 doc/conf.py: read version number from meson.build 2022-10-20 19:08:27 +02:00
5781f223f6 Document curl plugin .netrc and .curlrc behavior 2022-10-18 22:39:01 +02:00
e4c8ebe056 release v0.23.10 2022-10-14 23:51:41 +02:00
76b25a1377 output/alsa: add nullptr check for snd_pcm_name() return value
It is not explicitly documented whether snd_pcm_name() is allowed to
return NULL:
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#ga5031edc0422df8db1f70af056a12dd77

But apparently this is legal:
0222f45d11/src/pcm/pcm.c (L2761-L2762)

That's ... surprising!

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1645
2022-10-14 23:14:30 +02:00
ccc3ee663b java/File: remove assertions to work around -Wtautological-pointer-compare 2022-10-14 23:00:35 +02:00
0626661764 android/Context: fix typo in assert() variable name
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1644
2022-10-14 22:59:39 +02:00
31db04a3ca meson.build: suppress bogus clang 14 warning on libfmt headers 2022-10-14 22:54:34 +02:00
0c7163b9db subprojects: update expat 2022-10-14 22:46:30 +02:00
7d78cad8af doc/user.rst: update Android NDK requirement to 25b 2022-10-14 22:41:33 +02:00
912530ed20 test/meson.build: remove obsolete CURL workaround
This appears to have been fixed in some recent CURL version.
2022-10-14 22:41:33 +02:00
d3f37199b9 python/build/libs.py: update libnfs to 5.0.2 2022-10-14 22:41:33 +02:00
a4748d84b0 python/build/libs.py: update CURL to 7.85.0 2022-10-14 22:41:33 +02:00
8f847ec381 python/build/libs.py: update FFmpeg to 5.1.2 2022-10-14 22:41:33 +02:00
3a70f09dd3 python/build/libs.py: update libopenmpt to 0.6.6 2022-10-14 22:41:33 +02:00
568f63100b python/build/libs.py: update zlib to 1.2.13 2022-10-14 21:54:04 +02:00
3e25916b37 time/Parser: remove unused library 2022-09-30 18:17:03 +02:00
5f9438dae6 storage/curl: include cleanup 2022-09-30 18:16:46 +02:00
99e65c58ce storage/curl: make timestamp parsing more robust
According to the latest WebDAV specification (RFC4918),
timestamp string in the getlastmodified property is formatted
as rfc1123-date, such as "Sun, 06 Nov 1994 08:49:37 GMT".
However, to process responses from servers in the older style
format specified in RFC2518, timestamps in the HTTP-date format
had better be accepted.

As described in the libcurl api documentation, curl_getdate() can handle
timestamp strings in HTTP-date formats, including rfc1123-date.

https://www.rfc-editor.org/rfc/rfc4918#section-15.7
https://www.rfc-editor.org/rfc/rfc2518.html#section-13.7
https://curl.se/libcurl/c/curl_getdate.html
2022-09-29 18:19:30 +02:00
df71b07e9d storage/curl: fix can't get timestamp of remote file 2022-09-29 18:19:03 +02:00
2694195215 storage/curl: add noexcept and [[gnu::pure]] 2022-09-29 18:18:18 +02:00
66450d1f3c subprojects: update expat, fmt, sqlite3, vorbis 2022-09-28 11:34:33 +02:00
76efea3aa7 decoder/ffmpeg: add libfmt formatter for AVSampleFormat
Fixes compiler warning because formatting unscoped enums is deprecated
since libfmt 9.
2022-09-28 11:34:33 +02:00
7ab0dfc8ce Sets the curl proxy ssl verify options to the values of the host configuration options
This fixes 
2022-09-27 20:26:50 +02:00
15ff7c4cad Merge branch 'fix-oggflac-serial' of https://github.com/anthonyde/MPD into v0.23.x 2022-09-20 14:44:13 +02:00
9ab9b97f20 encoder/flac: only set a serial number for oggflac
This fixes a bug introduced in 87fa6bca where the FLAC encoder fails to
initialize unless libFLAC is built with Ogg support. When libFLAC is
built without Ogg support, FLAC__stream_encoder_set_ogg_serial_number
unconditionally returns false.
2022-09-16 17:58:41 -07:00
88d92aceab python/build/libs.py: update libFLAC to 1.4.0 2022-09-16 18:21:47 +02:00
a2ce4352c8 python/build/libs.py: update Boost to 1.80.0 2022-09-16 17:54:07 +02:00
84f43ccde8 LogInit: default to stderr on Windows
Don't require "log_file" setting, for "--no-config" operation.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1600
2022-09-06 21:04:53 +02:00
38704c9cf3 LogInit: improve systemd/journald comment 2022-09-06 21:03:56 +02:00
910d0ec92b test/net/meson.build: add missing dependency 2022-09-06 20:44:24 +02:00
3b05c89765 archive/iso9660: fix off-by-one assertion failure
Calling data[fill] could trigger an assertion failure if
fill==data.size(), even if we call it only to take the address.

Instead of doing that, this commit changes the code to pointer
arithmetic.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1556
2022-09-06 20:28:33 +02:00
e77b3fa46f increment version number to 0.23.10 2022-09-06 20:23:50 +02:00
12147f6d58 release v0.23.9 2022-08-18 18:20:54 +02:00
40bc60d6ae Main: load Android mpd.conf from ExternalFilesDir
See also https://github.com/MusicPlayerDaemon/MPD/issues/1061

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1570
2022-08-18 18:17:43 +02:00
7778210269 Main: move code to TryReadConfigFile() 2022-08-18 18:12:21 +02:00
6229210d51 Main: move code to LoadConfigFile() 2022-08-18 18:11:49 +02:00
5d0d5b5d97 Android/Context: allow type=nullptr in GetExternalFilesDir() 2022-08-18 18:11:49 +02:00
1aa3c1e543 java/String: add static method Optional() 2022-08-18 18:10:16 +02:00
b90e32fe4e Android/Context: look up methods once during startup 2022-08-18 18:10:14 +02:00
1f4df2a64d android/Environment: pass JNIEnv to all functions 2022-08-18 18:09:54 +02:00
2efc1db6a9 android/Environment: no namespace indent 2022-08-18 18:08:45 +02:00
e2d4654e20 filter/ReplayGain: invoke the MixerListener after volume change
This ensures that Partition::OnMixerVolumeChanged() invokes
MixerMemento::InvalidateHardwareVolume(), clearing the cached volume
level.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1526
2022-08-18 14:45:45 +02:00
2b8f1170a6 mixer/Control: use Mixer::IsGlobal() 2022-08-18 14:33:35 +02:00
5c4743441e mixer/All: use Mixer::IsPlugin() 2022-08-18 14:08:31 +02:00
cb288439a4 {android,win32}/build.py: make stdout/stderr unbuffered
Avoid excessive buffering if run by CI.
2022-08-08 23:48:23 +02:00
69f741e8a6 mixer/Memento: move IDLE_MIXER out of SetVolume()
Make this idle event per-partition.
2022-08-08 23:32:57 +02:00
4b4f47002b mixer/Volume: refactor to class MixerMemento, per partition
Eliminate global variables, convert them to MixerMemento fields.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1583
2022-08-08 23:30:27 +02:00
615c301961 mixer/Volume: remove logging (mostly useless) 2022-08-08 23:13:14 +02:00
dc07180e48 input/CdioParanoia: add options "mode" and "skip"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1529
2022-08-08 22:53:48 +02:00
d3b235bab5 input/CdioParanoia: move global variables up 2022-08-08 22:38:28 +02:00
7c920ddebe filter/ffmpeg: fix FFmpeg 5.1 deprecation warnings 2022-08-08 21:34:26 +02:00
bbc088ae4e This PR provides forward and backward compatibility at macos SDK 12.0. At SDK 12.0, API function names were changed essentially replacing
occurrences of the word Master/master with Main/main. This change was test built on two different systems.

1. macos 10.15.7 with Xcode 12.4 and clang 12.0.0 on x86_64
2. macos 12.5 with Xcode 13.4.1 and clang 13.1.6 on arm64 (Apple silicon M1)

It should be noted that on macos 10.15.7 with Xcode 11.2 and clang 11.0, MPD will not build.
The MPD documentation states that clang 11.0 is the minimum requirement,
but clang 11.0 produces compile errors. Apparently the macos version
of clang 11.0 is not fully compliant.
2022-08-08 17:39:29 +02:00
fe195257d8 python/build/libs.py: update FFmpeg to 5.1 2022-07-27 11:04:14 +02:00
57d5df8118 decoder/ffmpeg: fix FFmpeg 5.1 deprecation warnings 2022-07-27 11:04:09 +02:00
59792cb0b8 decoder/ffmpeg: wrap FFmpeg include in "extern C"
Commit ebae25d175 added that #include, but forgot to wrap it in
"extern C", so the linker tried to look up C++ symbols, causing linker
failure.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1582
2022-07-27 11:04:03 +02:00
cc557c4d60 meson: port ncpmc iconv solution
Properly deals with iconv, unlike the current solution. have_iconv fails
when libiconv CFLAGS are passed to the compiler. Tested under OpenWrt
with its CONFIG_BUILD_NLS, which adds libiconv include flags.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2022-07-20 08:03:24 +02:00
956c5faebb output/PipeWire: set app icon
Closes 
2022-07-12 13:59:05 +02:00
cd0396c1f1 test/run_decoder: remove bogus assert() 2022-07-12 11:59:14 +02:00
79f9b268bb increment version number to 0.23.9 2022-07-12 11:50:47 +02:00
b45f3c8deb Android release 0.23.8 2022-07-12 11:48:41 +02:00
f8a8de87e4 android/AndroidManifest.xml: update targetSdkVersion to 30
Required by Google Play.
2022-07-12 11:48:41 +02:00
2183f0553c android/meson.build: use apksigner instead of jarsigner
This is required for targetSdkVersion=30.

apksigner requires running zipalign first.
2022-07-12 11:48:41 +02:00
1f28790476 release v0.23.8 2022-07-09 01:05:38 +02:00
c8dae95eff output/PipeWire: after Cancel(), refill buffer before resuming playback
Deactivate the stream in Cancel().  This fixes stuttering after a
manual song change by refilling the whole ring buffer before
reactivating the stream.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1354
2022-07-09 01:03:36 +02:00
547a084c7e output/PipeWire: call pw_stream_flush() in Cancel()
Clear not only MPD's ring buffer, but also libpipewire's buffers, to
avoid playing some audio from the previous song after a manual song
change.

Fixes part 1 of https://github.com/MusicPlayerDaemon/MPD/issues/1354
2022-07-09 01:01:29 +02:00
493677ff81 output/PipeWire: skip Cancel() if already drained 2022-07-09 00:53:53 +02:00
6b430ba271 output/PipeWire: activate stream in Drain() 2022-07-09 00:53:20 +02:00
bc6924d303 output/snapcast: fix busy loop while paused
Removing the LockHasClients(); this code was copied from the "httpd"
output plugin, but unlike "httpd", the SnapCast output plugin does not
feed silence while paused, so we need to implement a delay to avoid
busy-looping the CPU.

As a side effect, this eliminates the suttering after resuming
playback, because the timer now gets reset even if there is a client.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1394
2022-07-08 22:55:41 +02:00
02b00f9146 output/PipeWire: don't force initial volume=100%
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1484
2022-07-08 18:25:41 +02:00
e807ed5870 output/PipeWire: ignore SPA_PROP_channelVolumes if n_values==0
After connecting, PipeWire sometimes sends SPA_PROP_channelVolumes
with no values, and this led to "volume=-NaN".
2022-07-08 18:13:33 +02:00
f08944253b output/PipeWire: check SPA_PROP_channelVolumes, not control name
Since PipeWire 0.3.53, there is no control name anymore, therefore the
name check doesn't work anymore, breaking volume change events.

This obsoletes the crash bug fix in commit 2ee57f9b0d
2022-07-08 18:06:36 +02:00
792d6584b9 output/PipeWire: move code to OnChannelVolumes() 2022-07-08 18:02:36 +02:00
7b45d01462 output/PipeWire: update field "volume" 2022-07-08 17:44:39 +02:00
5c17b2966a output/PipeWire: use std::accumulate 2022-07-08 17:44:08 +02:00
0c54f29446 output/PipeWire: document field "volume" 2022-07-08 17:30:57 +02:00
9c3cf39fdd output/PipeWire: catch exceptions in ParamChanged()
Fixes a potential crash bug.
2022-07-08 17:24:41 +02:00
d2fb229685 output/PipeWire: call ::SetVolume() in ParamChanged()
This is a lower-level function without some of the clutter of
PipeWireOutput::SetVolume() which is not needed in that case.
2022-07-08 17:21:17 +02:00
f55bc6682f output/PipeWire: move code to ::SetVolume() 2022-07-08 17:19:10 +02:00
6857286b42 decoder/Thread: don't scan for replay gain tags in PCM streams
This disables a long delay for playing songs from the cdio_paranoia
input plugin if ReplayGain is enabled.
2022-07-08 16:33:19 +02:00
c0d5bd2048 decoder/Thread: move code to DecoderControl::LockIsReplayGainEnabled() 2022-07-08 16:21:53 +02:00
666e5d7904 input/CdioParanoia: use integer modulo to calculate "diff" 2022-07-08 16:04:05 +02:00
3613407ac5 input/CdioParanoia: use typedef lsn_t 2022-07-08 16:03:04 +02:00
c32dceb4d4 input/CdioParanoia: remove loop from Read()
The Read() method is not required to fill the whole buffer.  By
returning as soon as at least one byte was read, we allow faster
cancellation.
2022-07-08 16:01:23 +02:00
5573e78364 input/CdioParanoia: skip seek if seeking within the buffer 2022-07-08 13:57:11 +02:00
807a19889f input/CdioParanoia: update offset only after successful seek
If seeking fails, don't leave the class with a wrong offset.
2022-07-08 13:57:11 +02:00
df7242de91 input/CdioParanoia: eliminate redundant field "lsn_relofs" 2022-07-08 13:36:59 +02:00
d62426f168 input/CdioParanoia: eliminate redundant field "lsn_to"
Use "size" instead.
2022-07-08 12:42:49 +02:00
1714cf3417 input/CdioParanoia: use IsEof() in Read() 2022-07-08 12:42:42 +02:00
1080c917be input/CdioParanoia: use std::min() 2022-07-08 12:37:21 +02:00
8eb3164878 input/CdioParanoia: fix crash if no drive was found
cdio_get_devices_with_cap() can return nullptr if no drive was found,
or it can instead return an empty list.  The latter caused MPD to
crash.
2022-07-08 12:05:20 +02:00
915c5442d1 input/CdioParanoia: use AtScopeExit() for cdio_free_device_list() 2022-07-08 12:03:57 +02:00
be0360d5e8 doc/user.rst: clarify .mpdignore documentation
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1532
2022-07-08 11:44:14 +02:00
4d6ae6ffdd output/PipeWire: add nullptr check to SetVolume()
If the PipeWire output has not yet been enabled and no thread_loop has
been created yet, a nullptr dereference in SetVolume() was possible
because nullptr was passed to pw_thread_loop_lock().
2022-07-08 11:32:59 +02:00
ecee6f415b mixer/MixerInternal: remember error details
If a mixer is not open, rethrow the original exception each time
setting the volume is requested.  This further improves error messages
sent to MPD clients.
2022-07-08 11:11:53 +02:00
47680f936b mixer/All: auto-open "global" mixers
If a mixer is "global", it is available even if the output isn't
open.  However, since the check was changed from IsEnabled() to
IsReallyEnabled(), enabled outputs have not yet been used have not
been "really" enabled yet, preventing using the mixer.

Fixes a regression by commit 35dbc1a90c
(part of https://github.com/MusicPlayerDaemon/MPD/pull/1480).

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1563
2022-07-08 11:05:26 +02:00
2d7181105d output/MultipleOutputs: SetVolume() throws on error
This reveals more about the nature of an error instead of just
returning "problems setting volume".
2022-07-08 10:56:55 +02:00
9bdc75524b python/build/libs.py: update CURL to 7.84.0 2022-07-08 10:13:52 +02:00
2f6ceb4949 python/build/libs.py: update OpenSSL to 3.0.5 2022-07-08 10:10:42 +02:00
cd933aa35f subprojects: update fmt and vorbis 2022-07-08 10:08:27 +02:00
138738075b libfmt 9 support
libfmt version 9 broke the API by removing fmt::make_args_checked().

Fixes https://bugs.debian.org/1014543
2022-07-08 10:06:53 +02:00
2ee57f9b0d output/PipeWire: add nullptr check, fixing crash with PipeWire 0.3.53
Since PipeWire 0.3.53, control names can apparently be nulled, leading
to crashes in applications assertion that the string cannot be
nullptr.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1558
2022-07-04 19:20:08 +02:00
5a5655b790 lib/curl/Adapter: catch and postpone exceptions in WriteFunction()
This fixes a std::terminate() crash in the CURL storage plugin when
PropfindOperation::OnHeaders() throws an exception after receiving a
non-207 status.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1559
2022-07-01 12:43:42 +02:00
b88d1e6820 lib/curl/Headers: make the comparison type "transparent" 2022-07-01 12:17:41 +02:00
19d2864c34 lib/curl/Headers: central type definition for the header map 2022-07-01 12:17:36 +02:00
29e3a17f26 lib/curl/Request: move code from SetupEasy() to Setup.cxx 2022-07-01 12:17:26 +02:00
252e9f736f lib/curl/Request: move code to class CurlResponseHandlerAdapter 2022-07-01 12:17:20 +02:00
5d08988dda lib/curl/Handler: fix typo 2022-07-01 12:17:17 +02:00
47ca4246aa lib/curl/Request: add constructor with CurlEasy parameter 2022-07-01 12:17:13 +02:00
f8338d4f00 lib/curl/Request: use std::size_t 2022-07-01 12:16:59 +02:00
5cf6032c90 lib/curl/Request: move code to SetupEasy() 2022-07-01 12:16:55 +02:00
8d8b77412d lib/curl/Request: add API docs 2022-07-01 12:16:50 +02:00
fd9114e7e2 doc/user.rst: fix neighbor plugin config block name 2022-06-08 12:57:27 +02:00
a3fba2f8f7 python/build/libs.py: update CURL to 7.83.1 2022-05-24 10:56:29 +02:00
e2b671f1b2 python/build/libs.py: add --disable-vulkan to FFmpeg configuration
Fixes Android build failure with NDK r25 beta4 because "vulkan_beta.h"
was not found.
2022-05-24 10:55:55 +02:00
2a35fbe29e python/build/libs.py: fix the OpenSSL SHA256 2022-05-24 10:55:55 +02:00
81cde72fd0 meson.build: suppress -Wstringop-overflow due to bogus libfmt warnings
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1536
2022-05-24 10:39:30 +02:00
bf9ffba4f7 doc/user.rst: fix playlist plugin name option
`playlist_plugin` blocks use `name` to identify the plugins.
2022-05-24 10:22:45 +02:00
c975d8b943 Fix deprecation warnings caused by name changes in OSX audio inerfaces 2022-05-24 10:20:47 +02:00
2730f91872 .github/workflows/build.yml: build everything, not just unit tests (Linux) 2022-05-23 21:32:42 +02:00
97ca85e155 .github/workflows/build.yml: verbose build (Linux) 2022-05-23 21:32:02 +02:00
39bb4c5871 .github/workflows/build.yml: build everything, not just unit tests 2022-05-23 21:28:28 +02:00
bdceb90c59 .github/workflows/build.yml: verbose build 2022-05-23 21:25:28 +02:00
8bd1b5228c lib/upnp/Compat: suppress -Wunused-but-set-parameter 2022-05-19 20:10:41 +02:00
a009e95afd .github/ISSUE_TEMPLATE/bug_report.md: add "Configuration" section 2022-05-19 09:26:21 +02:00
32aafb3572 .github/ISSUE_TEMPLATE/question.md: remove, we have GitHub discussions now 2022-05-19 09:25:00 +02:00
b577783cf0 .github/FUNDING.yml: remove, no funding
This was an experiment, but I decided I don't need that.
2022-05-19 09:24:22 +02:00
aa7b872a14 .github/workflows/build.yml: run "apt-get update"
The build has been failing for a week or two because the package lists
in the image are outdated.
2022-05-19 09:23:08 +02:00
c6f7f57776 apple/Throw: add missing <cstring> header
strlen() and strcpy() are provided by the <string.h> and <cstring>
headers (as functions in global and std namespaces, respectively).

Compilers MAY provide an implementation for either of the functions
without including the extra header but the existence of a declaration
without the header is not assured.
2022-05-19 09:08:44 +02:00
106ad08cd2 increment version number to 0.23.8 2022-05-09 23:12:17 +02:00
0341ca1b6a release v0.23.7 2022-05-09 23:04:30 +02:00
7581ea55db python/build/libs.py: update CURL to 7.83.0 2022-05-09 23:03:14 +02:00
fc9cee38d8 python/build/libs.py: update OpenSSL to 3.0.3 2022-05-09 23:03:14 +02:00
b175e4128d encoder/meson.build: always generate encoder/Features.h
Fixes regression from commit 85f9863e0a
2022-05-09 22:52:59 +02:00
97b07798b0 doc/protocol.rst: clarify repeat/single/random side effects 2022-05-09 22:50:57 +02:00
112fcd206d Merge branch 'fix-hls-seeking' of https://github.com/burrocargado/MPD into v0.23.x 2022-05-09 22:44:53 +02:00
11d1f56062 Fix seeking HLS on-demand streaming not working
This issue occurs when playing HLS streaming delivered
from a server that does not support partial requests.
The issue is reproduced as follows(using Ubuntu 20.04 PC):

1. Prepare HLS example content.

$ mkdir test
$ ffmpeg -i example.flac -vn -c:a aac -b:a 128000 -f hls -hls_list_size 0 test/output.m3u8
(ffmpeg 4.2.4 is used)

2. Prepare web server without partial requests support.
(Docker version 20.10.12 and NGINX official Docker image is used)

$ docker run --name tmp-nginx-container -d nginx
$ docker cp tmp-nginx-container:/etc/nginx/conf.d/default.conf .
$ docker rm -f tmp-nginx-container

Edit default.conf and add "max_ranges 0;" to "location / {...}".
This disables partial requests support,
removes 'Accept-Ranges: bytes' header from the server response.
Then, run the server:

$ docker run --name test-nginx -v $PWD/test:/usr/share/nginx/html:ro -v $PWD/default.conf:/etc/nginx/conf.d/default.conf -d -p 8080:80 nginx

3. Setup MPD to Play the next URL.

http://address-of-the-server:8080/output.m3u8

Seeking this stream results in "exception: Not seekable".
2022-05-07 12:18:56 +09:00
bd840d4638 decoder/plugins/FFmpegDecoder: fix IsSeekable()
AVFMTCTX_UNSEEKABLE signals the stream is not seekable
according to FFmpeg source code description:
8e98dfc57f/libavformat/avformat.h (L1181)
2022-05-07 09:48:04 +09:00
c3d393f214 tag/Id3Picture: fix unaligned access 2022-04-26 21:03:48 +02:00
f88fc0ca1a util/ByteOrder: add class PackedBE32 2022-04-26 21:03:05 +02:00
fb8d8242ab tag/ApeLoader: fix unaligned access
Fixes part 4 of https://github.com/MusicPlayerDaemon/MPD/issues/1490
2022-04-26 21:00:41 +02:00
f2a3dfd700 decoder/ffmpeg: add missing nullptr checks
Fixes part 1 of https://github.com/MusicPlayerDaemon/MPD/issues/1490
2022-04-26 20:51:57 +02:00
85f9863e0a meson.build: always enable Wave encoder for Snapcast
Even if the "wave_encoder" option is disabled (and no other encoder
plugins are enabled), forcefully enable the Wave encoder (if Snapcast
is enabled).

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1500
2022-04-26 20:13:43 +02:00
83572701f4 python/build/libs.py: update Boost to 1.79.0 2022-04-26 18:27:51 +02:00
fa7d7e9187 python/build/libs.py: update OpenSSL to 3.0.2 2022-04-26 18:27:51 +02:00
f818cde32c python/build/libs.py: update FFmpeg to 5.0.1 2022-04-26 18:27:51 +02:00
9da93cd887 python/build/libs.py: update zlib to 1.2.12 2022-04-26 18:27:51 +02:00
026e7ea32a update all subprojecs
Done with meson wrap update

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2022-04-26 18:01:53 +02:00
9659d19718 lib/upnp/Init: use if with initalizer 2022-04-26 17:58:33 +02:00
50d35c9677 upnp: use UpnpInit2 always
libupnp 1.14 removes the non 2 function. Fixes compilation there.

Signed-off-by: Rosen Penev <rosenp@gmail.com>

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1499
2022-04-26 17:57:48 +02:00
4260e78861 android: add gdb.sh
This script setup a dummy android native app folder and call ndk-gdb from it.

It needs a modification in ANDROID_NDK since ndk-gdb may attach to the wrong
pid, cf. comments in the script.
2022-04-26 17:47:54 +02:00
7342ae2e33 android: set application debuggable
This debuggable flag should not be set with release builds. Generally, graddle
is taking care of that.
2022-04-26 17:46:51 +02:00
35dbc1a90c mixer,output: prevent setting volume before outputs are really enabled
Previous versions of MPD would call SetVolume on enabled outputs before
they are ready, causing all of MPD to crash. Checking the really_enabled
flag prevents this, though it also prevents setting volume before the
player starts.

Before (with the PipeWire output):
  [i] ~$ mpc clear
  volume: 81%   repeat: off   random: off   single: off   consume: off
  [i] ~$ systemctl --user restart mpd.service
  [i] ~$ mpc volume 100
  MPD error: Connection closed by the server
  [i] ~ 1 $

After:
  [i] ~$ # mpd is freshly started w/o anything in the queue
  [i] ~$ mpc
  volume:100%   repeat: off   random: off   single: off   consume: off
  [i] ~$ mpc volume 80
  MPD error: problems setting volume
  [i] ~ 1 $ mpc
  volume:100%   repeat: off   random: off   single: off   consume: off
  [i] ~$
2022-04-26 17:45:29 +02:00
c7a4355153 outputs/pipewire: fix ParamChanged incorrectly setting volume
Previous versions of MPD would, on parameter change, set the PipeWire
volume before clearing the restore_volume flag, causing the call to
short circuit and do nothing. Instead, clear the flag before the call.
2022-04-26 17:44:19 +02:00
33a84a8ca2 output/shout: use shout_set_metadata_utf8() 2022-04-26 17:41:21 +02:00
1d04490ed3 output/shout: use shout_set_content_format() 2022-04-26 17:38:43 +02:00
4a30c2d79c output/shout: use shout_set_meta() 2022-04-26 17:24:49 +02:00
83072d6b9c output/shout: pass reference to Setup() 2022-04-26 16:49:18 +02:00
c779fc37eb output/shout: declare minimum version 2.4.0
This version was released 7 years ago, and it's reasonable to require
at least this version.
2022-04-26 16:46:36 +02:00
e08c13ad7e output/shout: add "noexcept" 2022-04-26 15:57:03 +02:00
2c82a6b2e0 output/shout: handle shout_metadata_add() errors
Fixes -Wunused-result
2022-04-26 15:56:55 +02:00
3929f17aef NEWS: mention the libiconv fix 2022-04-26 15:56:54 +02:00
ee39af3419 fix typo in comment 2022-04-24 04:14:17 +00:00
3882a5a263 src/lib/icu: fix iconv() detection when libiconv is installed 2022-04-20 16:10:39 +02:00
ac06088948 Make volume changes to apply to disabled software mixers.
Move audio output state check ahead of mixer check and force volume
applying even for disabled software mixed outputs.

This fixes incorrect software mixer volume that used to occur when
volume was changed while output being disabled.

This is easily reproduced with following sequence of commands on
multi-output software mixed MPD setup.

 mpc volume 38; mpc disable 3; mpc volume 88; mpc enable 3

On current MPD, following commands would result in output 3 playing at
volume 38, while all other enabled outputs would play at volume
88. Moreover, global volume would display average of outputs real
volumes. In my case, it's 75.

After applying this patch, following commands would produce expected
behavior. All outputs play at expected (88) volume. And volume is
correctly displayed as 88.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1423

Signed-off-by: Vitaly Ostrosablin tmp6154@yandex.ru


Signed-off-by: Vitaly Ostrosablin <tmp6154@yandex.ru>
2022-03-26 06:29:18 +01:00
a757eebfbb decoder/OggSyncState: allow skipping up to 64 kB after seek
This is more of what we did in commit 70bd35abe2 because it turns
out there are Ogg-Opus files with pages larger than 40 kB.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1487
2022-03-16 16:54:50 +01:00
2be4f89555 test/DumpOgg: new debug program 2022-03-16 16:51:44 +01:00
4a5c7d8261 increment version number to 0.23.7 2022-03-14 18:55:55 +01:00
f591193dda release v0.23.6 2022-03-14 18:55:47 +01:00
434869900e android/build.py: fix typo in error message
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1379
2022-03-14 18:49:50 +01:00
2aed7378cc TagAny: support CUE tracks
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1482
2022-03-14 18:42:31 +01:00
71cd6e6248 lib/xiph/meson.build: define FLAC__NO_DLL for static libFLAC build (Windows)
In libFLAC 0.3.4 (commit c9530118a4), the "dllimport" check has been
changed from "_MSC_VER" to "_WIN32", and now the MPD build is affected
by it.

Defining FLAC__NO_DLL disables the use of "dllimport", which allows
linking properly to the static libFLAC build.
2022-03-14 15:08:59 +01:00
c83294916a python/build/libs.py: update Boost to 1.78.0 2022-03-14 14:52:24 +01:00
603bbe0afd python/build/libs.py: update libnfs to 5.0.1 2022-03-14 14:52:24 +01:00
c361e235eb python/build/libs.py: update CURL to 7.82.0 2022-03-14 14:52:24 +01:00
8a59493d96 python/build/libs.py: update OpenSSL to 3.0.1 2022-03-14 14:50:06 +01:00
7ef86cbf9f python/build/libs.py: update FFmpeg to 5.0 2022-03-14 14:50:06 +01:00
c9530118a4 python/build/libs.py: update FLAC to 1.3.4 2022-03-14 14:31:13 +01:00
878d9abeb7 python/build/libs.py: update libogg to 1.3.5 2022-03-14 14:29:59 +01:00
2d705efe1c python/build/libs.py: update libmpdclient to 2.20 2022-03-14 14:29:22 +01:00
aeaef85507 WasapiOutputPlugin pause bug fix
Wasapi output plugin won't start playing after being paused

The cause is that the scope guard in the WASAPI work thread
(WasapiOutputPlugin.cxx, function WasapiOutputThread::Work(), in the
while (true) loop) is set up too 'late' in the execution. There is one
condition ("if (data_in_frames >= buffer_size_in_frames)") when it is
hit, the loop will continue without executing the scope guard. This
scope guard is responsible for emptying the buffer again, and if the
buffer is not emptied, the above mentioned condition will stay true.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1451
2022-03-14 14:26:00 +01:00
ebae25d175 plugins/FfmpegIO: include libavutil/mem.h
ffmpeg from current git master no longer exposes
av_malloc() nor av_free() through other included
headers. directly include libavutil/mem.h to fix
compilation with (as-yet-unreleased) ffmpeg.
2022-03-14 14:11:31 +01:00
5ad1a01d7a Remove bmp, tiff and add webp for coverimage filenames
- supporting bmp and tiff seems outdated
- webp is more widely used for coverimages
2022-03-14 14:09:23 +01:00
8f84e1befd decoder/plugins/FfmpegIo: return AVERROR_EOF at end of file
This part of the AVIOContext API is not documented :-(

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1448
2022-03-14 14:00:28 +01:00
9975905faf output/PipeWire: initialize field "stream" in Open()
Must be initialized for the check in SetVolume().
2022-03-09 14:29:46 +01:00
233184568c doc/protocol.rst: describe the FILTER argument to playlist{find,search} 2022-02-14 09:11:41 +01:00
59da778009 doc/user.rst: Clarify how MPD reads metadata
The writing and reading of metadata involves lots of different programs
and libraries. Therefore it is prudent to point out how exactly MPD
receives metadata. Ideally this helps to point users to the right place
if their tags are not picked up correctly.
2022-02-14 09:11:11 +01:00
108ce95b7c android/Receiver: fix indent 2022-01-26 14:43:47 +01:00
86e9ed5f3a decoder/opus: fix "readpicture" on Opus files
Don't return early from ScanOpusTags() if only
TagHandler::WantPicture() is set.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1413
2022-01-26 14:43:45 +01:00
fbecb05bf4 Fix Android build error: needs_exe_wrapper
lib/src/libmpdclient-2.19/meson.build:1:0: ERROR: Unknown options: "needs_exe_wrapper"

The "needs_exe_wrapper" option was incorrectly set under
[built-in options] rather than [properties].
2022-01-11 20:33:48 +01:00
4983703375 Android: Detect output change with ACTION_AUDIO_BECOMING_NOISY
Improves the changes made in 57687779be by
using AudioManager.ACTION_AUDIO_BECOMING_NOISY rather than listening for
wired headset unplug events or Bluetooth headset disconnect events. This
method is more flexible, allowing the feature to work on other types of
audio output device, as well as Bluetooth devices that don't set their
device class correctly. This change also has the benefit of being more
responsive, pausing the audio before it is rerouted to the built-in
speaker.

https://developer.android.com/guide/topics/media-apps/volume-and-earphones
2022-01-04 16:42:53 +01:00
3856224df9 lib/alsa/Error: add missing #include 2021-12-15 11:14:38 +01:00
6d4bedfc56 lib/alsa/Error: fix typo 2021-12-15 11:14:34 +01:00
bea821f194 doc/user.rst: add MixRamp documentation 2021-12-06 21:32:39 +01:00
4e276256c0 more braced init list conversion
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-12-06 09:16:04 +01:00
d0f9062b56 mpdconf.example: fix a few spelling typos 2021-12-05 22:58:45 +01:00
b9cc036703 .github/workflows/build.yml: rebuild branch v0.23.x 2021-12-03 23:00:42 +01:00
4e9b88559b SingleMode: convert "pure" to "const" 2021-12-03 16:09:34 +01:00
3452682a42 IcyMetaDataParser: move to tag/ 2021-12-03 16:07:39 +01:00
9262b24504 AudioCompress: move to pcm/ 2021-12-03 16:04:59 +01:00
a5fa43b526 fs/io: move to io/ 2021-12-03 14:35:41 +01:00
8681a3d74c replace TextFile references with LineReader 2021-12-03 14:22:56 +01:00
f9c4d88b12 fs/io/TextFile: add interface LineReader 2021-12-03 14:20:29 +01:00
799032505e io/uring/Queue: add method RequireSubmitEntry()
Fixes assertion failure when the submit queue is empty.
2021-12-03 13:58:39 +01:00
c8f174ac92 io/uring/Operation: disallow copying 2021-12-03 13:52:04 +01:00
047e169f3e util/BindMethod: merge MakeBind{Method,Function}Wrapper(), they are identical now 2021-12-03 13:51:56 +01:00
687327c9e8 util/BindMethod: merge structs {Method,Function}SignatureHelper into one 2021-12-03 13:51:56 +01:00
26dc37bd76 util/BindMethod: merge structs {Method,Function}WrapperGenerator into one 2021-12-03 13:51:55 +01:00
c693e4aa64 util/BindMethod: remove unused struct MethodWithSignature 2021-12-03 13:51:55 +01:00
acab731fef util/BindMethod: simplify MakeBindFunctionWrapper() 2021-12-03 13:51:55 +01:00
7e4ba3cb72 util/BindMethod: add MethodSignatureHelper::function_pointer 2021-12-03 13:51:55 +01:00
172c4d9c7d util/BindMethod: remove unnecessary template arguments from BindMethodWrapperGenerator 2021-12-03 13:51:55 +01:00
bd5f6cbc7b util/BindMethod: simplify more templates using "auto" template arguments 2021-12-03 13:51:55 +01:00
6fcd1c734b util/BindMethod: eliminate struct BindMethodWrapperGenerator2 2021-12-03 13:51:55 +01:00
eca097dbfb util/BindMethod: simplify more templates using "auto" template arguments 2021-12-03 13:51:55 +01:00
51ffafa011 util/BindMethod: use std::remove_reference_t 2021-12-03 13:51:25 +01:00
8dca602346 util/BindMethod: simplify BindMethod() 2021-12-03 13:51:18 +01:00
0ed24f3a05 util/IntrusiveList: disallow copying IntrusiveListHook 2021-12-03 13:50:05 +01:00
e25e0030e7 increment version number to 0.23.6 2021-12-01 20:01:22 +01:00
df4b6b92f2 release v0.23.5 2021-12-01 20:00:00 +01:00
1c69913eca decoder/flac: submit MixRamp only if there is actual data 2021-12-01 17:58:51 +01:00
cb5c6259fd decoder/mad: submit MixRamp only if there is actual data
Fixes MixRamp failures when a MP3 file has two ID3 tags, one of them
without MixRamp.
2021-12-01 17:19:53 +01:00
bf287fefb5 decoder/mad: move parse_id3_mixramp() to tag/Id3MixRamp.cxx 2021-12-01 17:11:36 +01:00
20bf1d68e6 MixRampInfo: move to tag/ 2021-12-01 17:09:02 +01:00
9bc4c168fd tag/MixRamp: rename to MixRampParser.cxx 2021-12-01 17:07:53 +01:00
3415049d1c test/tag/TestMixRampParser: include the header, not the .cxx file 2021-12-01 17:07:39 +01:00
a45949b597 tag/MixRamp: [[gnu::...]] attributes 2021-12-01 15:48:33 +01:00
6009d4abab tag/MixRamp: use std::string_view 2021-12-01 15:47:54 +01:00
16fb843c9b tag/MixRamp: fix typo which broken MixRamp
Fixes regression by commit 8e0d810968 which is 2 years old, and nobody
noticed.  D'oh, how embarassing!
2021-12-01 15:46:31 +01:00
36b333459b test/tag/TestMixRampParser: new unit test 2021-12-01 15:46:01 +01:00
4d3320233e test/test_mixramp: move to test/tag/ 2021-12-01 15:33:17 +01:00
933a1a41e6 lib/upnp/Discovery: use InjectEvent instead of DeferEvent
Fixes regression by commit 774b4313f2
2021-11-30 18:03:27 +01:00
1ff8626716 MSVC util/StringAPI.hxx add usage of MSVC compiler 2021-11-26 17:30:17 +01:00
c30466b84a net/IPv4Address: add method GetPortBE() 2021-11-26 16:25:43 +01:00
868f1a4431 net/UniqueSocketDescriptor, ...: include <utility> instead of <algorithm>
Since C++11, std::swap() lives in <utility>.
2021-11-26 16:25:29 +01:00
05f529fffd util/StringStrip: use [[gnu::...]] attributes 2021-11-26 16:24:55 +01:00
f01388559f .github/workflows/build.yml: fix the ccache.key 2021-11-26 13:32:48 +01:00
27edd4a610 .github/workflows: merge build-{linux,macos}.yml into one 2021-11-26 13:32:08 +01:00
cc421b04cd test/meson.build: add "protocol:gtest" where appropriate 2021-11-26 08:47:06 +01:00
3f2bc325a1 test/meson.build: fix test() indent 2021-11-26 08:40:40 +01:00
54686dfd79 test/meson.build: add dependencies on run_input
Fixes spurious unit test failures because run_input has not yet been
built.
2021-11-26 08:35:49 +01:00
f22cf02ed8 fix wrong namespace name
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-26 08:08:45 +01:00
5b51d0f733 use some auto
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-26 08:08:45 +01:00
e03f82636a const reference conversion
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-23 12:33:03 -08:00
d53d85bd79 remove unused includes
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-23 12:33:03 -08:00
4682ae0898 command/database: support relative offsets for "searchadd"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1337
2021-11-23 12:17:32 +01:00
fd5b195879 .github/workflows/build-macos.yml: use actions/setup-python@v1
Without it, BSFishy/meson-build defaults to /usr/local/bin/python,
which is Python 2.
2021-11-23 12:17:32 +01:00
bb5df9839d .github/workflows/build-macos.yml: install Meson, ninja and Boost 2021-11-23 12:17:32 +01:00
be34d55291 .github/workflows: add macOS build 2021-11-23 11:41:40 +01:00
c13911b171 .github/workflows: auto-build with GitHub Actions 2021-11-23 10:45:14 +01:00
6f83bdd6f3 Merge branch '1' of git://github.com/neheb/MPD 2021-11-23 10:39:07 +01:00
9bcd425a85 array conversions
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-23 01:38:10 -08:00
ec917f70d2 Merge remote-tracking branches 'neheb/2' and 'neheb/3' 2021-11-23 09:23:43 +01:00
40ce4eeb43 use cinttypes header
stdint.h is deprecated.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-22 23:30:36 -08:00
29ae84e199 manual braced init
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-22 23:30:04 -08:00
250011f016 return by braced init list
shorter

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-22 23:28:08 -08:00
e08c85ae2d doc/mpd.conf.5.rst: move ReplayGain documentation to user.rst 2021-11-22 22:25:04 +01:00
dcb5ca203c db/DatabasePlaylist: increment only one variable
Fixes "searchaddpl" bug emitting bogus error "Bad position".

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1338
2021-11-22 20:47:34 +01:00
77df5a8f24 lib/pcre: migrate to PCRE2
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1352
2021-11-22 19:32:45 +01:00
d6bebd2507 doc/conf.py: Set sidebar width to 300px to limit wrapping
This enhances readability in sidebar, especially for "User’s Manual" and
"Protocol" pages
2021-11-20 10:49:15 +01:00
f74996c02f Merge remote-tracking branches 'neheb/1', 'neheb/2', 'neheb/3', 'neheb/4' and 'neheb/5' 2021-11-20 07:55:24 +01:00
eea2d35d3a util/AllocatedString, ...: add missing include for std::exchange()
Fixes building with GCC 12.
2021-11-19 16:06:20 +01:00
d94e8bd82d queue/IdTable: include cleanup 2021-11-19 16:03:09 +01:00
b0c92e1a34 queue/IdTable: lazy-initialize the "data" array
With large "max_playlist_length" settings, the "data" array can be
very large, and initializing it during MPD startup causes page faults,
resulting in allocation of physical RAM.  This commit postpones the
initialization until the queue is really large, to avoid wasting
memory.
2021-11-19 16:00:39 +01:00
ead5bcf048 queue/IdTable: make size const 2021-11-19 15:51:10 +01:00
bdd268a524 doc/user.rst: update build dependencies on Debian Bullseye 2021-11-19 11:04:47 +01:00
e783c2bd2c util/LazyRandomEngine: use std::optional to avoid allocation
Signed-off-by: Shen-Ta Hsieh <ibmibmibm.tw@gmail.com>
2021-11-14 03:53:42 +08:00
837fc98638 use const references
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:18:33 -08:00
5deca66fdc add various nodiscard
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:17:26 -08:00
cfe2dd4147 use nullptr
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:16:19 -08:00
00f8d65a17 remove std::move
clang-tidy reports this is trivially copyable and thus std::move has no
effect.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:15:21 -08:00
4e0e4c00bf treewide: replace lock_guard with scoped_lock
SonarLint reports the latter to be better:

std::scoped_lock basically provides the same feature as std::lock_guard,
but is more generic: It can lock several mutexes at the same time, with a
deadlock prevention mechanism (see {rule:cpp:S5524}). The equivalent code
to perform simultaneous locking with std::lock_guard is significantly more
complex. Therefore, it is simpler to use std::scoped_lock all the time,
even when locking only one mutex (there will be no performance impact).

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:13:03 -08:00
a8c77a6fba Merge branch '1' of git://github.com/neheb/MPD 2021-11-11 10:33:17 +01:00
31aa6d0c4f use auto with make_unique
C arrays can be used with make_unique in C++17.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 01:33:03 -08:00
d051c4931d Merge branch '2' of git://github.com/neheb/MPD 2021-11-11 10:32:45 +01:00
94b0baceb0 convert address_family_ranking to std::array
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 01:27:31 -08:00
16feb261e2 increment version number to 0.23.5 2021-11-11 10:18:19 +01:00
f084bf7872 release v0.23.4 2021-11-11 10:16:36 +01:00
1112d3907a Revert "systemd: add "RuntimeDirectory" directive"
This reverts commit 552c30eae4.

It has caused various problems; for example, MPD wasn't able to write
the pid_file (which was already mitigated by commit a4e4217204).

And apparently, the socket file created in the same directory by
mpd.socket disappears when mpd.service (re)creates the directory.  I
could not reproduce this problem with 247.3, but maybe this is a bug
in older systemd versions?

Until we figure out why this happens, let's remove the
RuntimeDirectory directive.  A future MPD version may be launched as
regular user, not as root, which will eliminate one major problem with
RuntimeDirectory.
2021-11-11 10:16:13 +01:00
3464497880 command/database: add optional position parameter to "searchaddpl"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1328
2021-11-11 09:52:49 +01:00
651f57bced command/playlist: save only if at least one song was added 2021-11-11 09:50:31 +01:00
b4e72aba6c command/playlist: move code to SearchInsertIntoPlaylist() 2021-11-11 09:40:41 +01:00
061dd2dfef output/plugins: fix build error with clang and -stdlib=libc++
This fixes this build error observed with clang and -stdlib=libc++:

../mpd-0.23.3/src/output/plugins/PipeWireOutputPlugin.cxx:661:55: error: implicit instantiation of undefined template 'std::array<std::byte, 64>'
        std::array<std::byte, MAX_CHANNELS * MAX_INTERLEAVE> buffer;
                                                             ^
/usr/include/c++/v1/__tuple:219:64: note: template is declared here
template <class _Tp, size_t _Size> struct _LIBCPP_TEMPLATE_VIS array;
                                                               ^
2021-11-10 15:35:56 -05:00
5f4ec7de5b decoder/ffmpeg, lib/ffmpeg: make AVCodec pointers "const"
For libavcodec 59 support.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1333
2021-11-09 21:09:14 +01:00
6f81bb4b09 upnp: add option to configure interface for db plugin
Add an option to the UPnP database plugin to configure which interface
is used by upnp to discover servers.

upnp by default selects the first interface that is not loopback, which
in some cases might not be the desired interface. For example if wanting
to access a DLNA server over a VPN connection.

The "interface" option can now be set to the name of the desired
interface to achieve this.

The default behaviour remains unchanged.
2021-11-08 23:04:07 +01:00
4ed60a5711 upnp: expose interface configuration on UpnpInit2()
Adds the Interface Name as an argument to the *Init functions to make it
possible to select which interface is used by upnp to detect servers.

Currently "nullptr" is passed in to let the upnp library select an
interface, as before.
2021-11-08 22:53:01 +01:00
c93195c94b NEWS: fix typo 2021-11-05 14:45:43 +01:00
f30adac4bb doc/mpdconf.example: add comments recommending not to use log_file and pid_file 2021-11-05 09:06:27 +01:00
a4e4217204 Main: ignore the "pid_file" setting if started as systemd service
Commit 552c30eae caused problems for those people who still had a
"pid_file" setting (even though that is obsolete with systemd),
because now /run/mpd is owned by root:root (our mpd.service has no
User=mpd directive, so systemd starts MPD as root).

To work around this problem, and to be able to keep
RuntimeDirectory=mpd (which solved a problem of other MPD users), the
best compromise seems to just ignore the "pid_file" setting when it is
of no use.
2021-11-05 09:02:56 +01:00
8754d705a1 CommandLine: rename struct options 2021-11-05 08:57:12 +01:00
23d4a2d6a5 Main: pass struct options by reference 2021-11-05 08:56:05 +01:00
ce77b148d9 CommandLine: add option --systemd
This way, MPD can reliably detect whether it was started as systemd
service, which is better than checking sd_booted(), which only checks
whether systemd manages all services, but still MPD could be started
manually.
2021-11-05 08:51:49 +01:00
be3eca39e8 NEWS: add missing lines 2021-11-04 17:59:02 +01:00
3413b1aeb4 output/alsa: add option thesycon_dsd_workaround 2021-11-04 17:55:53 +01:00
356d13e9dd lib/alsa/HwSetup: add missing include 2021-11-04 17:55:15 +01:00
fa34bf0aaf Merge branch 'feature/win32-disable-openmpt123' of git://github.com/ibmibmibm/MPD 2021-11-04 15:11:26 +01:00
5d0941476a lib/alsa/Error: a std::system_error category for libasound errors 2021-11-04 14:59:00 +01:00
5ff0bbd0f8 lib/fmt/AudioFormatFormatter: add formatter for SampleFormat 2021-11-04 14:55:01 +01:00
a3764e533c python/build/libs.py: disable building libopenmpt cli
Signed-off-by: Shen-Ta Hsieh <ibmibmibm.tw@gmail.com>
2021-11-04 21:54:12 +08:00
3e05cba30e python/build/libs.py: update libopenmpt configure flags
Signed-off-by: Shen-Ta Hsieh <ibmibmibm.tw@gmail.com>
2021-11-04 15:23:24 +08:00
14b3c0f0af event/Loop: destruct the Uring::Manager in the destructor before assert()
Fixes assertion failure when the EventLoop gets destructed before
Run() was ever called.

Fixes https://bugs.debian.org/998310
2021-11-03 18:32:14 +01:00
67aff05051 increment version number to 0.23.4 2021-10-31 18:17:35 +01:00
19a101c3ac release v0.23.3 2021-10-31 18:13:10 +01:00
8da17a8211 doc/user.rst: add optimized build options to examples 2021-10-31 17:09:16 +01:00
2748929039 doc/user.rst: add -Dwrap_mode=forcefallback to Android/Windows examples 2021-10-31 17:08:59 +01:00
0c900a4bfa doc/user.rst: pass -Dandroid_debug_keystore=... to ./android/build.py 2021-10-31 17:03:37 +01:00
f1d5d70010 android/run-javac.sh: switch to Java 7 2021-10-31 16:55:40 +01:00
56ebc7637d python/build/libs.py: update FFmpeg to 4.4.1 2021-10-31 16:44:11 +01:00
996dd9fc8b python/build/libs.py: update libopenmpt to 0.5.12 2021-10-31 16:42:50 +01:00
056514d598 output/snapcast: reset unflushed_input after successful read
With the "wave" encoder, this has no effect, but it's more correct.
2021-10-31 16:35:42 +01:00
9a21bdfd6a output/snapcast: implement Pause()
This uncomments the code which had been present already in the first
Snapcast commit (copied from the "httpd" output plugin), but I
commented it because I did not know whether I needed to send silence
samples to all Snapcast clients.

As a side effect, this fixes playback when no Snapcast client is
connected; this was broken because Pause() always returned a positive
value when there were no clients.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1310
2021-10-31 16:26:29 +01:00
03f99dd26e db/update/Walk: use GetFilenameSuffix() instead of uri_get_suffix()
Unlike GetFilenameSuffix(), uri_get_suffix() removes the query string
first, which breaks file names with question marks in the name.
Therefore, uri_get_suffix() shall only be applied to remote URIs.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1316
2021-10-31 13:18:24 +01:00
bfb1b641f9 db/update/InotifyUpdate: fix use-after-free bug
Regression by commit 2d8847f428
2021-10-28 13:39:38 +02:00
72ba98c464 doc/protocol.rst: add missing backtick 2021-10-27 02:11:39 +03:00
dcd19c0592 config/Path: use StringView::Split() 2021-10-26 12:55:01 +02:00
109159e0f7 Permission: use StringView::Split() 2021-10-26 12:25:47 +02:00
409b877eea output/ao: include cleanup 2021-10-26 12:20:18 +02:00
c5bf7948ff fs/StandardDirectory: use the RUNTIME_DIRECTORY environment variable 2021-10-26 09:30:16 +02:00
b9f7127691 fs/StandardDirectory: add GetAppRuntimeDir() 2021-10-26 09:30:16 +02:00
1e6f5f012c fs/StandardDirectory: add GetUserRuntimeDir() 2021-10-26 09:30:16 +02:00
225d85fd9b fs/StandardDirectory: use "if" with initializer 2021-10-26 09:29:57 +02:00
1bb22f118d fs/StandardDirectory: add more pure/const attributes 2021-10-26 09:04:20 +02:00
552c30eae4 systemd: add "RuntimeDirectory" directive 2021-10-26 08:38:36 +02:00
48e8a26813 command/playlist: allow range in playlistdelete 2021-10-25 12:23:37 +02:00
ade847bc89 PlaylistFile: fold spl_move_index() into handle_playlistmove() 2021-10-25 12:13:45 +02:00
a6173e0eae command/playlist: add position parameter to "playlistadd"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1106
2021-10-25 12:10:47 +02:00
4529bb4a83 doc/protocol.rst: add "since" version notes 2021-10-25 08:47:23 +02:00
258ecb764f PlaylistFile: add class PlaylistFileEditor 2021-10-23 13:54:50 +02:00
6f595e9abb command/queue: add optional position parameter to "add"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1285
2021-10-23 13:12:44 +02:00
35c4c7e8bf command/queue: move #ifdef out of AddDatabaseSelection() 2021-10-23 13:09:04 +02:00
293ed924d1 command/queue: pass Partition to AddDatabaseSelection() 2021-10-23 13:06:31 +02:00
c8121176b3 output/alsa: add option "stop_dsd_silence" to work around DSD DAC noise 2021-10-23 12:25:32 +02:00
ee270f9b00 meson.build: log_dep is only needed internally 2021-10-23 12:08:43 +02:00
bf1d77a4d8 output/alsa: un-inline several methods 2021-10-23 12:02:27 +02:00
a9344fafe9 lib/alsa/AllowedFormat: use StringView::RemoveSuffix() 2021-10-23 11:43:31 +02:00
b8890726f2 lib/alsa/AllowedFormat: use std::string_view 2021-10-23 11:42:30 +02:00
0f84332654 output/alsa: make "mode" const 2021-10-23 11:39:59 +02:00
46c82259f7 output/Control: make config fields const 2021-10-22 20:22:22 +02:00
2d03823283 output/Control: fold Configure() into the constructor 2021-10-22 20:21:58 +02:00
bba144eca5 output/Control: use C++ initializers 2021-10-22 20:21:43 +02:00
9af73dad93 output/Multiple: remove unused method Add() 2021-10-22 20:21:35 +02:00
f0d66bf6a6 output/Control: pass rvalue reference to move constructor 2021-10-22 20:14:37 +02:00
5ad53a7554 output/Thread: remove duplicate code by calling InternalCloseOutput() 2021-10-22 19:54:47 +02:00
7b2e3331f2 output/Filtered: improve API docs 2021-10-22 19:54:38 +02:00
3cb44f6652 increment version number to 0.23.3 2021-10-22 12:50:11 +02:00
b7fdff46f2 release v0.23.2 2021-10-22 12:45:45 +02:00
e16109330d input/last: clear "uri" in OnCloseTimer()
Without clearing the "uri" field, the next Open() call attempts to
reuse the old InputStream, but it has already been closed, so Open()
always returns nullptr.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1300
2021-10-22 12:45:18 +02:00
72621531e0 protocol/Result: convert to Client method 2021-10-22 11:55:39 +02:00
0a48146efc client/Client: pass std::string_view to Write()
Almost all callers have string literal, and the length is known at
compile time.
2021-10-22 11:54:14 +02:00
0c4bf12bfd player/CrossFade: fix inverted check and wrong variable
The inverted check was introduced by commit 46d00dd85f, and commit
8ad17d25ef added a check for the wrong variable.  D'oh!

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1303
2021-10-22 11:49:38 +02:00
b8e0855ef3 output/pipewire: obey PipeWire's DSD bit order and interleave
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1297
2021-10-21 21:15:16 +02:00
6467502b9d output/pipewire: restore SampleFormat::DSD after ToPipeWireAudioFormat() call 2021-10-21 21:15:13 +02:00
15b67f20e5 output/pipewire: un-inline ParamChanged() 2021-10-21 20:11:22 +02:00
0825179f00 output/pipewire: add local reference variables 2021-10-21 20:02:59 +02:00
97211d0aad output/pipewire: rename field "buffer" to "pod_buffer" 2021-10-21 20:02:32 +02:00
029c499bfa output/pipewire: use std::fill_n() 2021-10-21 20:01:44 +02:00
0ba867ec16 output/pipewire: use MAX_CHANNELS, not SPA_AUDIO_MAX_CHANNELS
MPD supports only 8 channels, so MAX_CHANNELS is enough, the array
doens't need to be SPA_AUDIO_MAX_CHANNELS (which is 64).
2021-10-21 20:01:01 +02:00
866d147122 output/pipewire: make field "channels" unsigned 2021-10-21 19:59:48 +02:00
32851d1bc7 output/pipewire: DSD support
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1297
2021-10-20 11:39:54 +02:00
78257408b4 output/pipewire: report errors from the "state_changed" callback 2021-10-20 11:24:57 +02:00
f447b7615e output/pipewire: check pw_stream_connect() errors 2021-10-20 11:24:51 +02:00
1f780b7209 output/Thread: log exception details 2021-10-20 11:24:51 +02:00
04bf8a6b1a output/pipewire: fix memory leak in SendTag() 2021-10-20 10:16:36 +02:00
c4c64854d4 output/pipewire: evaluate errno after libpipewire function calls 2021-10-20 10:13:27 +02:00
17562dc90b output/pipewire: remove misplaced noexcept 2021-10-20 09:41:27 +02:00
7b24316734 output/pipewire: fix coding style 2021-10-20 09:41:10 +02:00
5fab107fd3 lib/nfs/FileReader: use the thread-safe InjectEvent
.. instead of DeferEvent, which is not thread-safe.  This caused
various playback problems, which was initially caused by the
DeferEvent/InjectEvent split in commit 774b4313f2

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1298
2021-10-20 09:38:09 +02:00
f31920e092 event/Loop: add thread assert() to AddDefer()
Currently fails in class NfsFileReader due to
https://github.com/MusicPlayerDaemon/MPD/issues/1298
2021-10-20 09:26:27 +02:00
eb111a10e7 output/pipewire: remove redundant prefix and newline from log message 2021-10-19 14:38:37 +02:00
80b09360c6 NEWS: mention the previous commit 2021-10-19 14:38:37 +02:00
5ccf78855d Implement SendTag for PipeWire output plugin 2021-10-19 14:31:40 +02:00
fd5a3b5880 client/Response: reimplement Error() without FmtError()
With libfmt versions older than 7, this leads to an endless recursion
between Error() and FmtError(), resulting in a crash due to stack
overflow.  D'oh!

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1295
2021-10-19 13:40:11 +02:00
6120c1360c neighbor/Glue: remove unreachable "throw" statement
Should have been removed by commit a8087dc12c
2021-10-19 13:40:11 +02:00
a8087dc12c neighbor/Glue: mention failed plugin name in error message 2021-10-19 13:29:00 +02:00
070c03dbf7 event/Thread, ...: fix printf->libfmt remains 2021-10-19 13:19:07 +02:00
0a9bec3754 increment version number to 0.23.2 2021-10-19 10:29:49 +02:00
fff25ac753 release v0.23.1 2021-10-19 10:27:28 +02:00
4f1e79b6b8 filter/ReplayGain: emit "mixer" event when replay gain changes volume
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1294
2021-10-19 10:03:21 +02:00
aa9933c0b5 output/pipewire: add noexcept 2021-10-19 08:58:50 +02:00
0697d1f859 output/pipewire: include cleanup 2021-10-19 08:57:33 +02:00
df033fa4aa NEWS: mention the previous commit 2021-10-19 08:56:32 +02:00
b941a7df83 Implement volume updates for pipewire output 2021-10-19 00:01:45 +02:00
31151cec3c command/playlist: "load" supports relative positions
This commit also increases the PROTOCOL_VERSION so clients can detect
the availability of the feature.
2021-10-18 22:08:22 +02:00
07e8c338df command/queue: move position parameter functions to separate library 2021-10-18 22:07:04 +02:00
b22d7218aa command/player, ...: use decimal notation
During the libfmt migration, I converted "%1.3f" to just "{:1.3}"
without the "f" suffix, but libfmt defaults to scientific notation,
which can break some MPD clients.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1291
2021-10-18 16:54:53 +02:00
d5be8c74b0 output/pipewire: attempt to change the graph sample rate
Requires PipeWire 0.3.32.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1283
2021-10-18 16:46:23 +02:00
c112cb60da output/snapcast: fix typo which caused "Failed to get chunk"
This bug caused a 9 second offset in all time stamps.  Due to that,
the Snapcast server thought the chunks are too old and discarded them.

Fixes https://github.com/MusicPlayerDaemon/MPD/discussions/1287
2021-10-18 16:40:11 +02:00
677fa4f9bc doc/plugins.rst: mention that the snapcast output requires a format 2021-10-17 20:01:21 +02:00
907af2ad02 Permission: refactor getPermissionFromPassword() to return std::optional
This replaces the output parameter (which is bad API design).  As a
side effect, it fixes the bad [[gnu::pure]] attribute added by commit
a636d2127 which caused optimizing compilers to miscompile calls to
that function.  "Pure" functions can be assumed to have no output
arguments, so the compiler can assume the function doesn't modify
them.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1282
2021-10-17 19:58:50 +02:00
6a2e7bbc02 protocol/ArgParser.cxx: Add missing #include <stdio.h>
Fixes a build problem on platforms where stdio.h is not included
transitively. snprintf() is defined in stdio.h.
2021-10-16 17:38:07 +02:00
771c46032f meson.build: add missing libfmt dependencies
Fixes https://github.com/MusicPlayerDaemon/MPD/discussions/1281

The problem occurred when there was libfmt-dev installed, but it was
too old (e.g. on Debian Buster), and Meson used the wrap fallback.
Those internal MPD libraries where the libfmt dependency was not
declared were still using the old system libfmt headers, which are not
ABI-compatible with MPD's own libfmt build.
2021-10-15 14:26:59 +02:00
85611aa456 storage/smbclient: add StoragePlugin.prefixes
Should have been part of commit
ef24cfa523

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1279
2021-10-15 10:24:30 +02:00
466b5cb08d neighbor/smbclient: FmtError() instead of FormatErrno()
Fixes part 2 of https://github.com/MusicPlayerDaemon/MPD/issues/1279
2021-10-15 09:40:36 +02:00
3f2f3251cb neighbor/smbclient: use [[gnu::pure]]
Fixes part 1 of https://github.com/MusicPlayerDaemon/MPD/issues/1279
2021-10-15 09:39:34 +02:00
8ae85f3991 doc/protocol.rst: move POSITION from "search" to "findadd"
Whoops, I misplaced this one.
2021-10-14 15:36:25 +02:00
781fe4ff28 increment version number to 0.23.1 2021-10-14 15:36:16 +02:00
163c59128e release v0.23 2021-10-14 15:25:21 +02:00
608896571c command/queue: add position parameter to "load"
Another one from https://github.com/MusicPlayerDaemon/MPD/issues/888
2021-10-14 15:11:11 +02:00
2e5ca1cbd2 command/database: add "position" parameter to "findadd" and "searchadd"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/888
2021-10-14 15:03:02 +02:00
680fb51c37 Permission: add "player" to default permission set
Forgot that in commit 9a766f4cd9
2021-10-14 14:58:38 +02:00
77d74b404e Permission: add option "host_permissions"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1115
2021-10-14 14:44:18 +02:00
a636d2127a Permission: add "pure" attributes 2021-10-14 14:26:51 +02:00
9a766f4cd9 Permission: split permission "player" from "control"
Some users want certain clients to fully control playback, but do not
want them to be able to trigger database update.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1124
2021-10-14 14:19:51 +02:00
8ad17d25ef player/CrossFade: do not cross-fade songs shorter than 20 seconds
From the feature request: "I generally like to have crossfade on, but
when it happens during such short tracks (e.g. 20 seconds or less) it
doesn't really sound good as those tracks are not really meant to be
crossfaded and intended to act as a bridge on their own."

Sounds reasonable.  This commit doesn't add an option, but hard-codes
the limit to 20 seconds.  If it turns out that users want to have it
configurable, we can still add the option.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1184
2021-10-14 13:47:24 +02:00
46d00dd85f player/CrossFade: move code to CanCrossFadeSong() 2021-10-14 13:42:27 +02:00
ec52b13449 player/CrossFade: add method IsEnabled() 2021-10-14 13:41:50 +02:00
cf6ca1b0ba player/CrossFade: use C++11 initializers 2021-10-14 13:38:42 +02:00
37bd6de658 db/simple: add option to hide CUE target songs
This reduces duplicates in the music database by hiding the original
song file when it is referenced by a CUE sheet.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1275
2021-10-14 13:28:37 +02:00
f7622ca332 db/update/Walk: move PurgeDanglingFromPlaylists() to Playlist.cxx 2021-10-14 13:12:10 +02:00
b82b56970b db/simple/Song: reorder fields for better packing 2021-10-14 12:55:02 +02:00
e4eb5b79c9 output/shout: move shout_new() call to Enable()
Don't allocate any memory until the output is really enabled.
2021-10-14 12:28:36 +02:00
1cfea20b22 output/shout: remove the defunct "timeout" option
The implementation was removed 12 years ago in commit f6455d5f79 and
nobody missed it.
2021-10-14 12:04:13 +02:00
efa3ffa8d8 Revert "db/update/playlist: remove non-existent targets while scanning"
This reverts commit 9200fa6d06.  It was
wrong because it works only if the target song has already been
scanned.
2021-10-14 11:50:41 +02:00
1b8c94d6b9 db/update/Playlist: move code to another UpdatePlaylistFile() method 2021-10-14 11:36:45 +02:00
cd5c1f3f45 db/update/playlist: remove empty playlist directories 2021-10-13 19:23:24 +02:00
9200fa6d06 db/update/playlist: remove non-existent targets while scanning 2021-10-13 19:23:24 +02:00
1bbe9896f6 Main: make inotify errors non-fatal 2021-10-13 18:55:05 +02:00
2d8847f428 db/update/InotifyUpdate: convert to class, no global variables 2021-10-13 18:47:56 +02:00
72f6e018e7 Log: remove the obsolete printf-style functions 2021-10-13 17:41:19 +02:00
2fbbd540bb more [[gnu::...]] attributes 2021-10-13 17:38:01 +02:00
18f64b5fb7 system/FatalError: remove obsolete library 2021-10-13 16:53:01 +02:00
d2a8b1e8a5 db/update/InotifySource: make errors non-fatal 2021-10-13 16:53:01 +02:00
184e8eca7c win32/Win32Main: throw on error 2021-10-13 16:37:56 +02:00
0a8886704a Main: move top-level exception handler to main()
Allows win32_main() to throw exceptions.
2021-10-13 16:37:34 +02:00
0712314d23 archive/{zzip,iso9660}: ignore file names which are invalid UTF-8
These malformed strings must not be transferred over the wire, because
the MPD protocol is defined to be UTF-8.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1274
2021-10-13 15:51:08 +02:00
f8cbba1850 util/Alloc: remove unused library 2021-10-13 14:48:16 +02:00
635ec3ce37 util/VarSize: use plain malloc() 2021-10-13 14:46:40 +02:00
8e71130e8a tag/FixString: use class AllocatedArray 2021-10-13 14:40:33 +02:00
ed7baf3ae1 tag/Id3Scan: use StringView::Strip() instead of duplicating the string 2021-10-13 14:32:43 +02:00
1e159af2ce tag/Id3Scan: merge duplicate code into InvokeOnTag() 2021-10-13 14:30:57 +02:00
dffed6e393 tag/Id3Scan: add class Id3String 2021-10-13 14:24:17 +02:00
bf656af555 playlist/SoundCloud: use AllocatedString for concatenation 2021-10-13 12:47:57 +02:00
d2b8852d19 playlist/SoundCloud: move code to TranslateSoundCloudUri() 2021-10-13 12:23:15 +02:00
7d4de71899 sticker/SongSticker: use AllocatedString for concatenation 2021-10-13 12:19:45 +02:00
e1c16d78e4 decoder/wavpack: use AllocatedString for concatenation 2021-10-13 12:15:57 +02:00
a49b49cba7 decoder/wavpack: fix WVC file support
The wrong variable was used.  This has been broken by commit
4eeea640f4 seven years ago - and nobody as noticed, d'oh!
2021-10-13 12:11:39 +02:00
f510564d9d more [[gnu::...]] attributes 2021-10-13 12:07:05 +02:00
1c4b484a56 avahi/Poll: use FineTimerEvent in AvahiTimeout
libavahi-client uses this one to schedule events immediately.
However, CoarseTimerEvent may be called too late, and cause timeouts.
2021-10-13 11:13:54 +02:00
b394d8d059 net/Resolver: include cleanup 2021-10-13 11:06:10 +02:00
a15c1c71d5 util/WritableBuffer: add WritableBuffer<void>::{FromVoid,ToVoid}() 2021-10-13 11:05:33 +02:00
8d679e7e00 util/IntrusiveList: add IntrusiveList::swap() 2021-10-13 11:04:42 +02:00
2b30ac2351 util/IntrusiveList: add another missing ToNode() call 2021-10-13 11:04:21 +02:00
1c97793b49 util/IntrusiveList: do not use the deprecated class std::iterator
Deprecated in C++17.  Since C++17, one is supposed to declare those 5
types manually.
2021-10-13 11:03:49 +02:00
4dae8b41da event/PipeEvent: new class wrapping SocketEvent 2021-10-13 10:45:55 +02:00
be8ed2f59e tag/Settings: use [[gnu::const]] 2021-10-13 10:37:26 +02:00
08491fcd86 tag/Format: use [[gnu::pure]] 2021-10-13 10:37:26 +02:00
abed633fcb tag/FixString: use [[gnu::pure]] 2021-10-13 10:37:26 +02:00
db2a9cb6d5 tag/Builder: use [[gnu::pure]] 2021-10-13 10:37:26 +02:00
7caeb3b0d8 tag/ParseName: use [[gnu::pure]] 2021-10-13 10:32:22 +02:00
08500be239 tag/VorbisComment: use [[gnu::pure]] 2021-10-13 10:31:51 +02:00
3ef7d8fecb tag/Tag: use [[gnu::pure]] 2021-10-13 10:31:51 +02:00
ffde7223b9 tag/Table: use [[gnu::pure]] 2021-10-13 10:31:51 +02:00
4e84fa4a00 RemoteTagCache: use [[gnu::pure]] 2021-10-13 10:31:51 +02:00
78e49928b6 command/QueueCommands: disallow moving the current song relative to itself
This was a no-op previously, but this operation makes no sense.
2021-10-07 22:55:41 +02:00
c0bcfe244c command/QueueCommands: reimplement relative "move"/"moveid" offsets
The existing implementation has been utterly broken forever; I cannot
explain what it actually does, but it doesn't do what the
documentation says.
2021-10-07 22:49:38 +02:00
e63ecd81ec command/QueueCommands: eliminate id lookup from handle_addid()
Use MoveRange() instead of MoveId().
2021-10-07 22:44:06 +02:00
c47a858d15 command/QueueCommands: move code to RequireCurrentPosition() 2021-10-07 22:21:00 +02:00
076c9a0dd9 command/QueueCommands: offset relative "addid" positions by one
Now, "+0" means "right after the current song" and "-0" means "right
before the current song".  Mnemonic: there are zero songs between the
current song and the newly added song.
2021-10-07 22:12:10 +02:00
3993176b76 command/QueueCommands: support relative offsets in "addid"
A similar feature was present long ago in MPD, but was deprecated in
version 0.16 because the implementation was broken.  This commit
re-adds the feature in a way that's well-defined and not broken.

Close https://github.com/MusicPlayerDaemon/MPD/issues/1221
2021-10-07 21:55:56 +02:00
16cad48641 command/QueueCommands: validate the "addid" position before adding the song
Validate early, so we avoid the rollback if an error occurs.
2021-10-07 21:27:07 +02:00
7a6d0c2efc command/Queue: move LookupRemoteTag() to the end
Skip the LookupRemoteTag() call if the MoveId() call fails.
2021-10-07 21:13:45 +02:00
f6035f2dda util/UriRelative: use std::string_view
Eliminates lots of implicit std::string temporaries.
2021-10-07 14:49:53 +02:00
c34a1e29de util/UriRelative: fix variable mixup 2021-10-07 14:44:41 +02:00
41a69027c2 test/util/TestUriRelative: add failing test for "./" prefix 2021-10-07 14:44:30 +02:00
711c614528 python/build/libs.py: update WildMidi to 0.4.4 2021-10-07 13:34:04 +02:00
6acb240f69 python/build/libs.py: update CURL to 7.79.1 2021-10-07 13:31:00 +02:00
45f3dd8b7a Revert "python/build/libs.py: remove flac, switch to Meson wrap"
This reverts commit 6ed4aff4d3.  The
Meson wrap is broken on non-x86, because it unconditionally includes
<cpuid.h> which is an x86 only header.
2021-10-07 13:28:17 +02:00
acc1bd6297 playlist/PlaylistSong: Remove dots from playlist file paths. 2021-10-07 13:15:40 +02:00
49ed9dae34 util/UriUtil: New uri_squash_dot_segments. 2021-10-07 13:14:54 +02:00
cf554d306d LocateUri: implement UriPluginKind::STORAGE properly
This way, URI schemes supported by arbitrary storage plugins are
allowed.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1270
2021-10-06 20:36:39 +02:00
ef24cfa523 storage/Plugin: add "prefixes" 2021-10-06 20:14:01 +02:00
5d35983298 decoder/openmpt: catch libopenmpt exceptions in scan_stream()
Fixes crash bug.
2021-10-06 20:14:01 +02:00
2dacb36789 LocateUri: throw std::invalid_argument instead of std::runtime_error
This should translate to ACK_ERROR_ARG instead of ACK_ERROR_UNKNOWN.
2021-10-06 19:26:33 +02:00
57a1403f08 output/pipewire: implement Delay(), fix busy loop while paused
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1265
2021-09-24 11:33:35 +02:00
bad3283182 output/pipewire: add flag "active", replaces some uses of "paused"
This way, we know whether we're explicitly "paused" or "not yet
activated because the ring buffer hasn't been filled yet".
2021-09-24 11:33:30 +02:00
6ed4aff4d3 python/build/libs.py: remove flac, switch to Meson wrap 2021-09-21 16:44:51 +02:00
e525465592 python/build/verify.py: support SHA256 2021-09-21 16:22:21 +02:00
10782f4c84 {android,win32}/build.py: use makedirs(exist_ok) 2021-09-21 16:04:31 +02:00
2a02576d6d python/build/meson.py: move c_args, ... to [built-in options]
As per Meson 0.56.0:
 https://mesonbuild.com/Machine-files.html#properties
2021-09-21 14:57:55 +02:00
9ea1578a97 lib/expat/meson.build: propagate the libexpat dependency
Fixes the build with libexpat from Meson wrap.
2021-09-21 14:38:00 +02:00
520028dcfc python/build/libs.py: remove libexpat, switch to Meson wrap 2021-09-21 14:08:23 +02:00
e98cef06c7 python/build/meson.py: remove --libdir=lib MultiArch workaround
Not necessary anymore since Meson 0.50.0:
 https://mesonbuild.com/Release-notes-for-0-50-0.html#libdir-defaults-to-lib-when-cross-compiling
2021-09-21 13:58:45 +02:00
aef0535c55 python/build/libs.py: remove libvorbis, switch to Meson wrap 2021-09-21 13:49:50 +02:00
6b1d0cb01d meson.build: disable compiler warnings for subprojects
Requires Meson 0.56.0:
 https://mesonbuild.com/Release-notes-for-0-56-0.html#per-subproject-warning_level-option
2021-09-21 13:48:16 +02:00
f23ecf00da meson.build: set per-subproject "default_library"
Requires Meson 0.54.0:
 https://mesonbuild.com/Release-notes-for-0-54-0.html#per-subproject-default_library-and-werror-options
2021-09-21 13:41:45 +02:00
a1c1e26875 meson.build: require Meson 0.56.0
I want to use per-subproject warning_level (0.56.0), default_library
(0.54.0).
2021-09-21 13:39:44 +02:00
410b8711f2 lib/curl/meson.build: add -DCURL_STATICLIB on Windows
Necessary since commit 6acf81d5ae
2021-09-21 13:24:35 +02:00
6acf81d5ae python/build/libs.py: build CURL with cmake 2021-09-21 12:30:39 +02:00
4eb56d844e python/build/libs.py: update Boost to 1.77.0 2021-09-21 12:22:17 +02:00
5faf6d061f python/build/libs.py: build expat with cmake 2021-09-20 23:23:20 +02:00
d5a9f6d79d python/build/libs.py: build libogg, libvorbis with cmake 2021-09-20 23:23:20 +02:00
2699889342 python/build/cmake.py: use CMAKE_TOOLCHAIN_FILE
Let cmake know that we're cross-crompiling.
2021-09-20 23:14:13 +02:00
e4f933361e python/build/libs.py: update OpenSSL to 3.0.0 2021-09-20 22:54:02 +02:00
6f278977e9 build/python/project: add build(), calls _build()
Prepare to add some code around the _build() call.
2021-09-20 22:54:02 +02:00
4f2f705dca build/python/make: rename build() to build_make()
Eliminate conflict with other Project classes.
2021-09-20 22:54:02 +02:00
f31e38145d python/build/cmake.py: some ccache support 2021-09-20 22:54:02 +02:00
0231622169 build/python/cmake: add "windows_configure_args" 2021-09-20 22:46:54 +02:00
937423dbcf event/Loop: check the quit flag after RunDeferred()
Allow DeferredEvents to call EventLoop::Break().
2021-09-10 12:14:18 +02:00
40483d8478 fix wrong emplace usage
emplace already calls std::pair. No need for it again.

No need to emplace when calling std::make_shared.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-09-07 21:14:37 -07:00
6ec5089cc9 remove std::make_pair
make_pair is an old C++98 function that can be replaced by modern
shorter constructs.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-09-07 21:13:22 -07:00
15f419e1cb Update user.rst
NB: Check the sysconfdir setting to determine where mpd will look for mpd.conf; if you expect mpd to look for /etc/mpd.conf the sysconfdir must be '/etc' (i.e., not 'etc' which will result in mpd looking for /usr/local/etc/mpd.conf):
 
.. code-block:: none
 
 meson configure output/release |grep sysconfdir

If this is not /etc (or another path you wish to specify):

.. code-block:: none

 $ meson configure output/release -Dsysconfdir='/etc' ; meson configure output/release |grep syscon
  sysconfdir              /etc                                               Sysconf data directory
2021-09-06 12:41:41 -04:00
bdd8c34c67 Merge branch 'move' of git://github.com/neheb/MPD 2021-08-29 06:47:05 +02:00
c9a9248c9f java/Class: use Java::LocalObject
This eliminates all but one DeleteLocalRef() call.
2021-08-28 08:09:54 +02:00
31f7fede30 java/GlobalRef: remove method Set(), always require initialization 2021-08-28 08:08:30 +02:00
917fe549b0 java/Object: use type aliases 2021-08-28 08:05:57 +02:00
8e430e55af Java/GlobalRef: add LocalRef cast constructor 2021-08-28 08:04:20 +02:00
9e61bda592 java/String: add class StringUTFChars() 2021-08-27 12:30:43 +02:00
56997290d7 io/BufferedOutputStream: add method Discard() 2021-08-27 12:06:36 +02:00
d2f84f3df8 io/BufferedOutputStream: allow specifying the buffer size 2021-08-27 12:06:20 +02:00
9da28e5c73 io/BufferedOutputStream: more API documentation 2021-08-27 12:06:02 +02:00
d1f9b06f84 io/BufferedOutputStream: add WriteT() 2021-08-27 12:05:26 +02:00
f9f3306db9 io/BufferedOutputStream: use std::size_t 2021-08-27 12:05:06 +02:00
19d19cd737 fs/io/BufferedOutputStream: avoid including windows.h
Include the most specific header documented by MSDN instead.
2021-08-27 12:04:44 +02:00
b1175acb59 util/StringView: hard-code C++17 2021-08-27 12:01:31 +02:00
672278e5fd util/StringView: use [[gnu::]] attributes 2021-08-27 11:59:37 +02:00
da155f8822 util/StringCompare: use [[gnu::]] attributes 2021-08-27 11:58:25 +02:00
4026ef63b6 util/StringAPI: use [[gnu::]] attributes 2021-08-27 11:57:56 +02:00
b282682ba5 use using instead of typedef 2021-08-27 11:57:33 +02:00
ad00926e1b util/AllocatedArray: add method release() 2021-08-27 11:24:50 +02:00
0b774df375 prevent use after move
These should be equivalent anyway.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-26 13:38:36 -07:00
53ffcf455c make several member functions const
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-26 13:15:52 -07:00
9ca64d5fb3 filter/Chain: eliminate, just use a chain of TwoFilters instead
The ChainFilter class is extremely complicated code, and will grow to
be even more complicated when the Filter interface gets extended.
Let's just remove it; we can easily chain many TwoFilters instead.
2021-08-26 17:45:23 +02:00
bd79354f32 filter/TwoFilters: add ChainFilters() 2021-08-26 17:42:25 +02:00
49dcac5c21 filter/TwoFilters: add class PreparedTwoFilters 2021-08-26 17:36:19 +02:00
38a4b0d8d5 filter/TwoFilters: fix include guard 2021-08-26 14:36:52 +02:00
a224225e48 pcm/AudioFormat: use std::size_t 2021-08-26 13:42:15 +02:00
7d7fe756b3 pcm/AudioFormat: use [[gnu::pure]] 2021-08-26 13:42:15 +02:00
1cb7fe12ff pcm/AudioFormat: add noexcept 2021-08-26 13:37:36 +02:00
8a29805767 Merge tag 'v0.22.11'
release v0.22.11
2021-08-24 22:19:38 +02:00
94c196108d release v0.22.11 2021-08-24 22:15:22 +02:00
263d1ba002 Main: playlist_directory defaults to "/sdcard/Android/data/org.musicpd/files/playlists"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1233
2021-08-24 22:12:27 +02:00
2dba06dc34 android/Context: add GetExternalFilesDir() 2021-08-24 22:03:53 +02:00
811860c3b4 android/Context: use [[gnu::pure]] 2021-08-24 21:54:22 +02:00
8439119e24 filter/ffmpeg: support double-precision samples
Insert an "aformat" filter which converts double-precision to
single-precision.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1235
2021-08-24 13:45:57 +02:00
b5b40d8235 filter/ffmpeg: automatically retry with "aformat"
If DetectFilterOutputFormat() fails to determine the output format,
insert an "aformat" filter which attempts to force a specific output
format.

Fixes part 2 of of https://github.com/MusicPlayerDaemon/MPD/issues/1235
2021-08-24 13:31:13 +02:00
b904f8af03 lib/ffmpeg/Filter: add FilterContext::MakeAformat() 2021-08-24 13:30:17 +02:00
ebfbb74f9e lib/ffmpeg/DetectFilterFormat: return AudioFormat::Undefined() on EAGAIN 2021-08-24 13:30:03 +02:00
7b4225aa1f lib/ffmpeg/Filter: add ParseSingleInOut()
Merge some duplicate code.
2021-08-24 13:29:08 +02:00
71a5311b06 lib/ffmpeg/Filter: eliminate class FilterContext
Since AVFilterContext are freed automatically, this wrapper class
serves no purpose.  Let's remove it.
2021-08-24 13:04:34 +02:00
a62a35e1db lib/ffmpeg/Filter: remove FilterContext destructor
Fixes potential double-free bugs which currently did not occur because
the destructors happened to be called in the right order.
2021-08-24 12:56:05 +02:00
ca2439f595 filter/ffmpeg: pass "channel_layout" instead of "channels" to buffersrc
Fixes part 1 of https://github.com/MusicPlayerDaemon/MPD/issues/1235
2021-08-23 21:38:13 +02:00
f9a0db716a android: build with NDK r23 2021-08-23 20:58:19 +02:00
34aa67ea87 Merge remote-tracking branches 'neheb/6', 'neheb/5', 'neheb/3', 'neheb/2' and 'neheb/1' 2021-08-23 20:36:26 +02:00
18be8c3318 Fix compile error on macOS 11.15.2 (introduced by commit 30e3ef4) 2021-08-21 11:16:22 -05:00
1d7a8f992f clang-tidy: use auto
The type is duplicated otherwise

Found with modernize-use-auto

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-21 00:53:23 -07:00
da1783cdff clang-tidy: remove pointless const
Found with readability-const-return-type

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-21 00:51:21 -07:00
20d74bb07e clang-tidy: replace loop with std::all_of
Found with readability-use-anyofallof

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-21 00:49:36 -07:00
0f7a0b04ca replace loop with find_if
loop is wrong anyway. It's missing a break;

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-21 00:48:30 -07:00
40c6a214e3 unique_ptr/new to make_unique
The latter is easier to read and is the "correct" thing to do.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-20 23:54:14 -07:00
cfe024ea13 command/file: return directory_uri if real_uri is unset
Prevent a segfault when accessing album art.

Fix  
2021-08-17 10:55:43 +02:00
993d85125e increment version number to 0.22.11 2021-08-17 10:55:10 +02:00
bedcf1cce5 Merge branch 'exp2' of git://github.com/neheb/MPD 2021-08-17 10:53:36 +02:00
30e3ef4c8e constexpr/std::array conversions
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-16 21:05:56 -07:00
4c5fea96e4 constexpr global variable conversion
Found with cppcoreguidelines-avoid-non-const-global-variables

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-16 20:58:21 -07:00
46600931e4 clang-tidy: use default
Found with modernize-use-default

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-16 20:48:28 -07:00
a2387210bf time/FileTime: move code to SystemClock.hxx 2021-08-10 19:53:53 +02:00
d7e7adb496 time/FileTime: add ChronoToFileTime() 2021-08-10 16:16:15 +02:00
45354a421c time/FileTime: preserve the FILETIME resolution
Don't truncate the FILETIME to second resolution to pass it to
std::chrono::system_clock::from_time_t(); instead, calculate the
offset between the FILETIME epoch and the
std::system_clock::time_point epoch, and use that to initialize the
time_point directly.
2021-08-10 15:16:59 +02:00
9fc3c60910 time/FileTime: add FileTimeToChronoDuration() 2021-08-10 15:13:22 +02:00
1976003e91 time/FileTime: allow negative times 2021-08-10 15:13:16 +02:00
488afc47d4 time/FileTime: use uint_least64_t 2021-08-10 15:12:49 +02:00
017814adc7 test/time/TestFileTime: new unit test 2021-08-10 15:12:34 +02:00
7f94af8b2c test/time/TestISO8601: disable on Windows for now 2021-08-10 15:07:19 +02:00
09d74f05c3 python/meson: set exe_wrapper=wine for Windows builds
Allows running the unit tests on Linux.
2021-08-10 15:04:54 +02:00
1af8694ef6 python/meson: set needs_exe_wrapper=true only for Android targets 2021-08-10 15:00:58 +02:00
b8eb9b466a python/meson: split the f.write() call and use f-strings 2021-08-10 15:00:58 +02:00
bd9e449b69 python/project: re-add support for version suffix
Got lost in commit 0f56ddb805
2021-08-10 15:00:58 +02:00
f3d67115d7 output/wasapi: check ENABLE_DSD before setting dsd_mode 2021-08-10 15:00:58 +02:00
ee6603ed38 test/meson.build: add missing dependencies on libfmt 2021-08-10 14:31:49 +02:00
0dacde32f2 output/pipewire: append output name to PW node name 2021-08-10 11:30:25 +02:00
528e05f025 output/pipewire: add config option "remote" 2021-08-10 11:28:29 +02:00
269583f5dd output/pipewire: allow specifying a target by its name 2021-08-10 11:17:16 +02:00
7c9f4f7e4f output/pipewire: create inactive stream, fill ring_buffer first
This avoids underruns at the start of playback.
2021-08-10 10:50:42 +02:00
00fd692eba output/pipewire: wait for buffer to fill before resuming 2021-08-10 10:48:25 +02:00
668c3782b2 output/pipewire: smaller ring buffer, 500ms should be enough 2021-08-10 10:43:56 +02:00
1e0af2dadf output/pipewire: add type alias for boost::lockfree::spsc_queue 2021-08-10 10:43:54 +02:00
4ea2ea2a52 output/pipewire: update nbytes after calling PcmSilence()
This was missing in commit 8a243e6e28
2021-08-10 10:43:28 +02:00
8a243e6e28 output/pipewire: call pw_stream_flush() only if really draining
If draining was not requested, generate silence instead if there is no
data in the ring buffer.

The problem is that pw_stream_flush() appears to disable the stream
permanently, even though there is no state_changed callback - the
stream state remains at PW_STREAM_STATE_STREAMING, but the stream is
defunct.  I have no idea why and I havn't found any documentation
about it.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1219
2021-08-10 06:30:58 +02:00
d33aa01000 output/pipewire: reset the "paused" flag
This was missing in commit 4d1ce7023b
2021-08-09 19:31:22 +02:00
bd893e6336 Merge tag 'v0.22.10'
release v0.22.10
2021-08-06 18:21:59 +02:00
64c39af556 release v0.22.10 2021-08-06 18:16:59 +02:00
04eb911a51 mixer/alsa: use cached values to work around rounding errors
This replaces 967af60327 with a more
effective workaround.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/822
2021-08-06 18:16:37 +02:00
351b39e0c5 mixer/alsa: skip the snd_mixer_handle_events() call in alsa_mixer_elem_callback()
snd_mixer_handle_events() has already been called by
DispatchSockets().  This way, we can also skip the exception handler.
2021-08-06 18:03:36 +02:00
3b6d4e6673 mixer/alsa: move alsa_mixer_elem_callback() into the AlsaMixer class 2021-08-06 18:01:19 +02:00
e8f328d8ad mixer/alsa: move code to GetPercentVolume() 2021-08-06 17:56:30 +02:00
5f5b5f63af mixer/alsa: move code to NormalizedToPercent() 2021-08-06 17:55:59 +02:00
ad6e303047 mixer/alsa: move code to GetNormalizedVolume() 2021-08-06 17:53:45 +02:00
b0e9538855 build/openssl: pass --cross-compile-prefix to ./Configure 2021-08-06 17:30:47 +02:00
694debd4cc build/openssl: pass RANLIB=... to "make install"
The "install_dev" target runs ranlib during installation, and this
can break the Android build.
2021-08-06 17:28:28 +02:00
0f56ddb805 python/build/libs.py: update OpenSSL to 3.0.0-beta2 2021-08-06 17:22:41 +02:00
dde77ec6bd python/build/libs.py: update CURL to 7.78.0 2021-08-06 17:20:52 +02:00
5d73eda115 doc/plugins.rst: move filter graph URL to ffmpeg.org 2021-08-06 17:20:52 +02:00
1985786ed2 db/simple: prune CUE entries from database for non-existent songs
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1019
2021-08-05 20:26:21 +02:00
8e0d39ae94 db/update/Playlist: prepend "../" only for relative URIs
Prepending "../" to absolute URIs would break them.
2021-08-05 20:19:33 +02:00
1761fb14af fs/Traits: add PathTraitsUTF8::IsAbsoluteOrHasScheme() 2021-08-05 20:09:06 +02:00
ef2fc4e6f6 db/simple/Directory: remove obsolete API doc 2021-08-05 19:05:03 +02:00
b979245d6c decoder/Bridge: call UpdateStreamTag() only if there is no pending seek
If UpdateStreamTag() gets called while an initial seek is pending, the
result will never be submitted to a MusicChunk.  By avoiding the
UpdateStreamTag() call in that case (by moving UpdateStreamTag() to
after the PrepareInitialSeek() check), the song_tag is preserved until
UpdateStreamTag() is called again from SubmitData().

This fixes missing tags in the "httpd" output.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1137
2021-08-05 18:02:45 +02:00
a74b07728e tag/Tag: add Merge() which takes Tag pointers 2021-08-05 17:36:14 +02:00
7d69cbbda7 tag/Tag: Merge() returns Tag, MergePtr() returns std::unique_ptr<Tag> 2021-08-05 17:32:23 +02:00
955502f881 output/oss: enable DoP
Explanation

This adds support for DOP using the PcmExport function if the macro
ENABLE_DSD is defined. If enabled within the config-file using "dop",
the boolean dop_setting will be true. If DSD input is encountered and
the setting is on, it is checked whether the oss-device supports the
required samplerate. If that is the case, dop_active is set to true
and conversion of the input is prevented. If the sample rate is not
supported, conversion to S32 is requested. When playing back, the
PcmExport is used to pack the incoming stream into PCM.  Reasoning

This is required for OSs without the required driver support for
native DSD playback that also have no ALSA. Mainly *BSD users are the
target audience for this functionality, as ALSA here is only a proxy
without full functionality.  Requirements

    DAC that supports the DOP standard
    Building with OSS, DSD and S32-Format

Supported Formats / Required PCM Formats

DSF, DFF and WavPack-DSD will work.

DSD64, 1 Channel -> S24:176.4kHz (untested, lack of time / missing samples)
DSD64, 2 Channel -> S24:352.8kHz
DSD64, 4 Channel -> S24:705.6kHz (untested, lmissing equipment)
DSD128, 1 Channel -> S24:352.8kHz (untested, lack of time / missing samples)
DSD128, 2 Channel -> S24:705.6kHz
DSD256, 1 Channel -> S24:705.6kHz (untested, lack of time / missing samples)
Changes

    inclusion of required files
    adding new domain for logging
    adding dop_satisfied private function
    adding required member variables for storing dop state and for dop-packing
    adding dop boolean parameter to many functions that are required to act a little differently when dop is active

Testing

This has been tested to work with a Sabaj Da2 on FreeBSD, where the
red status indicator LED clearly shows that DSD playback is taking
place, instead of purple for "hi-res" which is seen when converting.
Issues

I have not tested this with S24 and right now AFMT_S32_NE is
required. If not defined, ENABLE_DSD will be undef'ed. This will be
addressed in a bit, however no DAC which supports DOP but not 32Bit is
known to me. Also, AFMT_S32_NE is not defined when building on FreeBSD
which is why this is just blatantly defined in the file at the moment.
Additionally, the new dop-option is not added into any documentation
whatsoever.
2021-08-05 16:21:43 +02:00
dee5d1b87b output/oss: replace the AudioFormat field with 3 raw OSS integers
This simplifies Reopen().
2021-08-05 16:03:53 +02:00
d42342e0ba output/oss: check returned value in oss_try_ioctl() 2021-08-05 15:53:30 +02:00
8da3f8c6a7 output/oss: oss_try_ioctl() throws on EINVAL
Eliminate some duplicate code.
2021-08-05 15:47:11 +02:00
c8c553c75c pcm/Export: add method IsDopEnabled() 2021-08-05 15:35:11 +02:00
c97aabe43a Merge branch 'v0.22.x' 2021-08-05 15:17:07 +02:00
17b0ac75ca output/oss: always enable PcmExport for alsa_channel_order
We need this even when AFMT_S24_PACKED is not available, for the
correct channel order in multi-channel files.  Internally, MPD uses
FLAC channel order, but OSS uses the same channel order as ALSA.
2021-08-05 15:11:54 +02:00
bde64a13e2 tag/Builder: do not acquire tag_pool_lock if TagItem list is empty 2021-08-05 14:32:58 +02:00
96875921b7 tag/Builder: use std::swap() in move operator
This way, we save the overhead for acquiring the tag_pool_lock.
2021-08-05 14:28:37 +02:00
551c941b5a tag/Builder: don't ignore the result of tag_pool_dup_item
Also, use RemoveAll() instead of directly clearing TagBuilder::items in
most cases, as its elements represent references that must be released.

Closes 
2021-08-05 14:25:55 +02:00
624c77ab43 tag/Builder: another missing RemoveAll() call 2021-08-05 14:25:05 +02:00
ba13b4b5d6 tag/Builder: use RemoveAll() to give up references 2021-08-05 14:23:48 +02:00
4b2d9e544c tag/Pool: add [[nodiscard]] 2021-08-05 14:20:59 +02:00
97c43954e8 input/tidal: remove defunct unmaintained plugin
This plugin has been defunct for several years.  Tidal has not ever
replied to any of my emails, so they're apparently not interested in
MPD support.
2021-08-05 13:52:05 +02:00
b77acd35f7 output/winmm: fix struct/class mismatch 2021-08-05 11:40:47 +02:00
4873159872 meson.build: add "fallback" option to fmt dependency (for older Meson versions) 2021-08-05 11:28:23 +02:00
968624035c mixer/pipewire: new plugin 2021-08-05 10:57:37 +02:00
b838bf3109 output/pipewire: un-inline StateChanged() 2021-08-05 10:48:17 +02:00
4d1ce7023b output/pipewire: implement Pause() 2021-08-04 17:26:54 +02:00
52577ac87a output/pipewire: implement Cancel() properly 2021-08-04 17:24:49 +02:00
9fa3984a2f input/icy: adjust offset at end of stream in Read()
ProxyInputStream::Read() assigns the `offset` field, which is the
wrong offset because it does not consider Icy metadata removed from
the stream.  Therefore, after every ProxyInputStream::Read() call,
IcyInputStream::Read() needs to override this offset.  This was
missing at the end of the stream, when Read()==0.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1216
2021-08-02 16:40:04 +02:00
239698cb5a output/pipewire: set channel positions 2021-07-30 15:55:37 +02:00
e55de6e9f0 output/pipewire: implement Drain() 2021-07-30 15:28:01 +02:00
cfaf2ed03c output/pipewire: move code to CheckThrowError() 2021-07-30 15:24:20 +02:00
6015960871 output/pipewire: reset the "interrupted" flag in Cancel()
This fixes seeking.
2021-07-30 15:20:32 +02:00
26328cc915 output/pipewire: detect connection errors 2021-07-30 14:31:06 +02:00
cd512f0b40 output/pipewire: replace usleep() with with pw_thread_loop_wait() 2021-07-30 14:31:04 +02:00
be14dd59a8 output/pipewire: remove obsolete TODO comment 2021-07-30 13:50:55 +02:00
97e5787ff7 output/pipewire: call libpipewire only while holding the lock
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1210
2021-07-30 13:49:22 +02:00
6975d3ca4b output/pipewire: switch from pw_main_loop to pw_thread_loop
We need this for pw_thread_loop_lock().
2021-07-30 13:42:59 +02:00
cdca27e6bb decoder/Bridge: fix libfmt string 2021-07-30 13:32:27 +02:00
5355335f19 db/simple/ExportedSong: check src.OwnsTag(), not this->OwnsTag()
this->OwnsTag() accesses fields that are not yet initialized.
2021-07-30 13:10:09 +02:00
5b775ca5b4 decoder/ffmpeg: check if long_name is not null 2021-07-28 16:05:15 +01:00
ea95da3b1a archive/meson.build: add missing libfmt dependency 2021-07-26 23:26:07 +02:00
57687779be Android: add option to pause MPD when headphones disconnect 2021-07-26 19:02:47 +01:00
64fa76c568 command/file: support "albumart" for virtual tracks in CUE sheets
Instead of checking for "cover.jpg" in the virtual directory
representing the CUE sheet, check its enclosing directory.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1206
2021-07-16 09:04:35 +02:00
19a44076cf command/file: pass directory uri to read_stream_art() 2021-07-16 08:31:58 +02:00
809a18913a fs/Traits: add overload GetParent(string_view) 2021-07-16 08:30:34 +02:00
5eab2d96f4 output/winmm: fix struct/class mismatch 2021-07-16 08:30:34 +02:00
716784f632 increment version number to 0.22.10 2021-07-16 07:23:00 +02:00
d39b11ba5d include <utility> for std::forward
Fixes
../git/src/Log.hxx:121:42: error: no member named 'forward' in namespace 'std'
        LogFormat(LogLevel::ERROR, e, fmt, std::forward<Args>(args)...);

Signed-off-by: Khem Raj <raj.khem@gmail.com>
2021-06-29 19:34:28 -07:00
b29a43b4d7 decoder/mad, ...: more libfmt logging 2021-06-25 20:52:08 +02:00
f60a42e0b6 Log, client/Response: adapt to libfmt 8.0.0 API changes 2021-06-25 20:29:25 +02:00
85b0029ba2 meson.build: add missing dependencies on libfmt 2021-06-25 20:28:54 +02:00
0e0f46a1e0 Log: remove unused Format functions 2021-06-24 21:40:12 +02:00
6f539cfcd6 Partition, ...: use libfmt for logging 2021-06-24 21:40:11 +02:00
0185d58a2b Log: add libfmt support 2021-06-24 21:14:42 +02:00
eb630ca655 doc/user.rst: rectify admin permission
Updating the database no longer requires the `admin` permission, only
`control` is needed (changed in 2abad0f479).

See also: 
2021-06-24 16:44:38 +02:00
d7df5e1c90 LogBackend: pass std::string_view to Log() 2021-06-24 13:43:13 +02:00
e4e4576a39 Merge tag 'v0.22.9'
release v0.22.9
2021-06-23 21:02:06 +02:00
18628bf89e release v0.22.9 2021-06-23 20:56:13 +02:00
2052b461af Fix android build error when confronted with package versions ending in +revision_information
The script seems to assume package version numbers always end in numeric versions with an optional alpha-suffix. Alas, were it only so simple... Sometimes the package is called fizzbang-1.2.3+release_info in which case the build fails. No more!

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1177
2021-06-23 20:53:46 +02:00
5019bdcd52 TagAny: invoke ScanGenericTags() on remote files
This fixes reading ID3 tags on remote files with the commands
"readcomments" and "readpicture".

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1180
2021-06-23 20:49:30 +02:00
8be0bcbdb9 doc/plugins.rst: mention default libsamplerate type 2021-06-23 15:51:31 +02:00
af72a22ed8 doc/user.rst: document restore_paused 2021-06-23 15:50:41 +02:00
6ed9668fea doc, README.md: update IRC server name/URL 2021-06-23 15:48:42 +02:00
175d2c6d29 Main: use AtScopeExit() to call ZeroconfDeinit()
Make sure that ZeroconfDeinit() gets called even if startup fails with
an exception.  Fixes an assertion failure because an Avahi TimerEvent
is still active.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1192
2021-06-22 20:31:45 +02:00
f789451007 doc/plugins.rst: fix PipeWire link 2021-06-19 21:29:37 +03:00
36680607d0 meson.build: use some warning options for plain C as well 2021-06-01 11:14:28 +02:00
fc54877c6b meson.build: merge duplicate warning flags to test_common_flags 2021-06-01 11:04:27 +02:00
6af7be4a45 add constexpr
Found with cppcoreguidelines-interfaces-global-init

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-05-31 13:45:39 -07:00
ab487b9a99 Android: use startForegroundService() in Android 8+
Fixes the error:

 IllegalStateException: Not allowed to start service Intent { cmp=org.musicpd/.Main (has extras) }: app is in background
2021-05-31 20:45:31 +02:00
ac59ec34f9 decoder/ffmpeg: fix build failure with FFmpeg 3.4
av_demuxer_iterate() was added in libavformat 58.9.100.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1178
2021-05-31 18:10:06 +02:00
82da57b7ce decoder/ffmpeg: suppress -Wunused with libavformat<58.6.100 2021-05-31 16:49:48 +02:00
aa6dac9bd2 db/proxy: suppress -Wunused with libmpdclient<2.12 2021-05-31 16:49:08 +02:00
220d2bf026 clang-tidy: add explicit deleted constructors
Found with cppcoreguidelines-special-member-functions

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-05-30 22:47:20 -07:00
9ef1cf15a9 clang-tidy: default virtual destructors
Found with cppcoreguidelines-special-member-functions

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-05-30 22:46:46 -07:00
679b3bc00f output/print, command/player: print bool as integer
Fixes protocol breakage after commit 0440c41cba

libfmt is too clever for the MPD protocol!

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1175
2021-05-28 18:02:00 +02:00
1f9e32c35e NEWS: fix typo 2021-05-28 15:46:38 +02:00
36410daaa4 queue/PlaylistEdit: fix inverted check
Regression by commit 471c37be59

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1135
2021-05-28 13:56:01 +02:00
38bfef7d0b Merge branch 'add-openmpt-decoder' of git://github.com/GrimReaperFloof/MPD 2021-05-28 13:53:43 +02:00
724754f16c Fix std::to_string warning for booleans in openmpt decoder 2021-05-27 20:47:45 +02:00
4d32454697 android/LogListener: pass formatted message to OnLog() 2021-05-27 16:21:36 +02:00
4db882f666 android/LogListener: cache the jmethodID 2021-05-27 16:14:43 +02:00
a83bf97b98 android/LogListener: un-inline the constructor 2021-05-27 16:13:22 +02:00
262e1957b7 lib/icu/Converter: use libfmt 2021-05-27 16:09:56 +02:00
792411384d protocol/ArgParser: add function MakeArgError()
Replaces FormatProtocolError().
2021-05-27 16:01:44 +02:00
78b0ff83e8 client/Response: include cleanup 2021-05-27 15:59:06 +02:00
23613355f3 client/Response: remove unused method FormatV() 2021-05-27 15:16:35 +02:00
0d97eba7a5 client/Response: refactor FormatError() to use libfmt 2021-05-27 15:15:47 +02:00
18efda719e client/Response: remove unused method Format() 2021-05-27 15:14:54 +02:00
42239a30eb client/Response: use Fmt() in FormatError() 2021-05-27 15:05:42 +02:00
a26bf261a9 input/last: call Close() in Open()
Prevents a possible bug which occurs when the caller-provided open()
function throws; then the "uri" field is never set.
2021-05-27 14:04:28 +02:00
c692286c67 input/last: clear "uri" field in Close()
Prevent false negative after the stream was closed automatically after
20 seconds.
2021-05-27 14:03:33 +02:00
43a9dc7082 Add note about emulate_amiga_type requiring libopenmpt 0.5 2021-05-26 23:43:38 +02:00
6f64fa070d Add repeat count setting to openmpt decoder 2021-05-26 23:43:38 +02:00
dc5b9d989b Backwards compatibility with older libopenmpt versions than 0.5 2021-05-26 23:43:38 +02:00
9e407f5989 Change WritableBuffer<uint8_t> to AllocatedArray<std::byte> 2021-05-26 23:43:38 +02:00
fec6aac0f1 Code deduplication: move mod_loadfile() into ModCommon.cxx 2021-05-26 23:43:38 +02:00
541c31c879 Add openmpt decoder plugin 2021-05-26 23:43:38 +02:00
4ee0a06e18 Merge branch 'v0.22.x' 2021-05-26 13:15:29 +02:00
3775766605 NEWS: mention new FFmpeg/ID3v2 tags 2021-05-26 13:07:03 +02:00
38e24208f6 decoder/ffmpeg: support the tags "album-sort", "artist-sort" 2021-05-26 13:04:47 +02:00
fbaedf2262 decoder/ffmpeg: support the "sort_album" tag
From libavformat/mov.c.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1173
2021-05-26 13:03:47 +02:00
8f3341cefb decoder/ffmpeg: add comment 2021-05-26 13:03:41 +02:00
4ec4bab3a9 decoder/ffmpeg: remove "year" tag
This mapping was added 11 years ago in commit 766b9fd453, but FFmpeg
doesn't appear to support it.
2021-05-26 13:03:27 +02:00
6d567bcd35 decoder/ffmpeg: fix ArtistSort and AlbumArtistSort mapping
These were added 11 years ago in commit 766b9fd453, but I cannot find
any evidence in the FFmpeg repository that these names were ever
supported.  This commit adds the tags as they are currently present in
libavformat/mov.c.
2021-05-26 13:03:26 +02:00
4f75eb9bfe output/pipewire: remove unreachable "return" statement 2021-05-26 11:57:57 +02:00
d2bd12822f Merge branch 'v0.22.x' 2021-05-26 11:57:41 +02:00
363d9f0180 db/update/Walk: load all .mpdignore files of all parent directories
When updating everything, this did work, but if updating only a
subdirectory, the ".mpdignore" in the parents were not used.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1172
2021-05-25 22:42:44 +02:00
db0682a469 db/update/Walk: move code to LoadExcludeList() 2021-05-25 22:38:01 +02:00
7a6823dcdf zeroconf/AvahiPoll: the struct timeval is an absolute time point
Fixes broken libavahi-client timeouts.
2021-05-25 22:25:45 +02:00
bce144a232 zeroconf/AvahiPoll: move code to Schedule() 2021-05-25 22:23:55 +02:00
0cef84cac6 zeroconf/AvahiPoll: rename "timer" to "event" 2021-05-25 22:23:55 +02:00
56c0733b42 meson.build: disable -Wsuggest-override with GCC 8 2021-05-25 22:23:55 +02:00
0b0acb3981 meson.build: add more C++ warning flags 2021-05-25 22:03:49 +02:00
1375dcc4ec meson.build: sort warning options 2021-05-25 21:49:03 +02:00
6aeb0e335b meson.build: add comment for -Wno-non-virtual-dtor 2021-05-25 21:48:19 +02:00
c1e2537851 meson.build: add comment for clang-only warning options 2021-05-25 21:45:39 +02:00
8c690fb737 decoder/mad: move variable declaration into "case" 2021-05-25 21:34:09 +02:00
dad1c21b59 zeroconf/avahi: move variable declaration into "case" 2021-05-25 21:34:09 +02:00
dd10b2bd61 meson.build: remove warning options implied by -Wall -Wextra 2021-05-25 21:24:44 +02:00
48c7c540df meson.build: use add_project_arguments() instead of add_global_arguments()
Don't propagate MPD-specific compiler flags to subprojects.
2021-05-25 21:08:06 +02:00
281270cd2a meson.build: remove unused variables common_cflags, common_cxxflags 2021-05-25 21:07:05 +02:00
02502514f6 meson.build: require clang 7 (remove bug workaround) 2021-05-25 21:06:55 +02:00
1bc02123f9 meson.build: remove "-pedantic", implied by Meson
Meson adds "-Wpedantic" in warning_level 3 (which is MPD's default).
2021-05-25 21:01:15 +02:00
3488a47c41 subprojects/sqlite3.wrap: add SQLite wrap 2021-05-25 20:51:03 +02:00
fd82d67678 sticker/Database: pass NarrowPath to sqlite3_open()
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1171
2021-05-25 18:45:45 +02:00
e66c12105b lib/sqlite/meson.build: add missing external dependency on libsqlite 2021-05-25 18:41:43 +02:00
8a9d678bac Merge branch 'v0.22.x' 2021-05-25 18:21:42 +02:00
dbe12a6b90 util/RuntimeError: Disable format-security for gcc
Fixes building under GCC 11
2021-05-25 18:19:19 +02:00
0440c41cba client/Response: add method Fmt() based on libfmt 2021-05-25 16:01:56 +02:00
a9c704b76e meson.build: libfmt integration 2021-05-25 15:48:49 +02:00
d3a680cc87 meson: set only sanitizers for fuzzer when unspecified
That is when meson option b_sanitize is not used
2021-05-24 09:03:16 +02:00
62fc4d5cf4 increment version number to 0.22.9 2021-05-24 09:03:07 +02:00
0cca1b138c Merge tag 'v0.22.8'
release v0.22.8
2021-05-22 17:35:30 +02:00
14465be847 release v0.22.8 2021-05-22 17:33:36 +02:00
0e49de867d input/last: add nullptr check to Open(), fixes assertion failure
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1168
2021-05-22 17:33:25 +02:00
f2e4529707 increment version number to 0.22.8 2021-05-22 17:32:00 +02:00
d3576a1b71 input/last: add nullptr check to Open(), fixes assertion failure
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1165
2021-05-21 19:30:36 +02:00
96707c0426 Merge tag 'v0.22.7'
release v0.22.7
2021-05-19 18:43:19 +02:00
e016cc8940 lib/upnp/meson.build: auto-disable UPnP without CURL/expat 2021-05-19 14:37:13 +02:00
34f636ffc3 Change WritableBuffer<uint8_t> to AllocatedArray<std::byte> 2021-05-19 09:54:06 +02:00
a134f692bf Code deduplication: move mod_loadfile() into ModCommon.cxx 2021-05-19 09:53:39 +02:00
d747576793 Merge branch 'npu' of git://github.com/neheb/MPD 2021-05-19 09:48:12 +02:00
d9578f6427 Merge branch 'flac-ogg' of git://github.com/jprjr/VGMPD 2021-05-19 09:33:42 +02:00
b2cec7a0a3 Merge branch 'v0.22.x' 2021-05-19 08:09:05 +02:00
85db2d6704 db/proxy: split search into chunks to avoid exceeding the output buffer
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1130
2021-05-19 08:04:50 +02:00
22ebb2bdd5 db/proxy: send "window" as separate parameter to SendConstraints() 2021-05-19 07:51:48 +02:00
e108568082 db/proxy: require libmpdclient 2.11 or later
Remove lots of #ifdefs.
2021-05-19 07:46:42 +02:00
360381e65d doc/plugins.rst: mention the minimum MPD version 2021-05-19 07:46:42 +02:00
3ead778664 doc/plugins.rst: add libmpdclient website link 2021-05-19 07:45:47 +02:00
4fc08e39b4 db/proxy: require MPD 0.20 or later
Allows using ranges, always.  This is required to fix
https://github.com/MusicPlayerDaemon/MPD/issues/1130 without adding
more runtime conditionals.
2021-05-19 07:41:04 +02:00
a2bdac571a Merge branch 'v0.22.x' 2021-05-17 19:33:15 +02:00
87fa6bca54 flac encoder: enable Ogg FLAC and Ogg chaining
refactors GenerateOggSerial into a generic GenerateSerial
utility, under the util lib.

libFLAC may be encoded without Ogg support. If Ogg support is disabled,
libFLAC will still export Ogg-related methods (like setting a serial
number), and throw a runtime error when initializing an Ogg stream.

GenerateOggSerial does not depend on libogg. Refactoring it into
a generic GenerateSerial prevents having to add build-time checks
for libogg within the FLAC encoder plugin.
2021-05-15 11:31:01 -04:00
c3226a3195 doc/conf.py: Copyright 2021 2021-05-11 17:57:14 +02:00
51671af5a4 doc/conf.py: move "~git" suffix to release 2021-05-11 17:52:24 +02:00
2908f6565b doc/conf.py: update version number to 0.23~git 2021-05-11 17:49:26 +02:00
a0334d1d94 Add resampling mode setting to modplug decoder 2021-05-07 19:48:52 +02:00
423f2df5e0 pcm/Volume: drop support for GCC older than 8 2021-04-20 20:01:43 +02:00
0122dc8452 util/BindMethod: drop support for GCC older than 7 2021-04-20 20:01:08 +02:00
95ad1b0cc6 use [[gnu::pure]] instead of gcc_pure
This is semi-standard and doesn't require the util/Compiler.h header.
2021-04-06 14:09:21 +02:00
52f46b94e9 util/AllocatedString: add concatenating constructor 2021-04-06 14:06:16 +02:00
e07e0bc9c1 util/AllocatedArray: include cleanup 2021-04-06 14:05:29 +02:00
4a1c231734 net/SocketError: use constexpr 2021-04-06 13:59:58 +02:00
fd0e958e95 net/SocketError: use auto 2021-04-06 13:58:46 +02:00
3d814115c8 net/SocketError: change "const" to "pure" 2021-04-06 13:58:32 +02:00
ca726a0110 util/StringBuffer: make capacity() static
This allows using it in constant expressions.
2021-04-06 13:46:07 +02:00
e01710cbd1 util/DereferenceIterator: simplify operator->()
This makes it compatible with containers storing std::unique_ptr.
2021-04-06 13:45:32 +02:00
c87a4a7d08 util/DereferenceIterator: fix static_cast in operator->() 2021-04-06 13:45:10 +02:00
b59170b702 Java/Exception: simplify RethrowException() 2021-04-06 13:35:59 +02:00
a237db556a java/File: add non-static GetAbsolutePath() overload 2021-04-06 13:35:59 +02:00
285ba54fe5 java/String: remove unnecessary env parameter 2021-04-06 13:35:59 +02:00
ee86434a89 java/String: add const 2021-04-06 13:35:59 +02:00
95d5efbfe6 java/Ref: add nullptr comparison 2021-04-06 13:35:59 +02:00
c33f206ce8 java/Ref: add nullptr constructor 2021-04-06 13:29:35 +02:00
2d95ac2e94 Java/String: inherit the super class constructor 2021-04-06 13:29:24 +02:00
f58c14a74a Java: no namespace indent 2021-04-06 13:29:13 +02:00
a52ce7bb7b java/Ref: add move operator 2021-04-06 13:27:11 +02:00
16d187b7ed java/Ref: remove const, add default initialiser 2021-04-06 13:26:54 +02:00
296ec4d07c java/Ref: add nullptr check to destructor
May allow the compiler to optimize calls away.
2021-04-06 13:26:29 +02:00
6e58fd1583 lib/curl/Multi: reword API documentation 2021-03-29 20:19:21 +02:00
c5fec4ac2a lib/curl/Multi: move operator bool() down 2021-03-29 20:19:21 +02:00
fe2ca1ddef lib/curl/Multi: rename parameters 2021-03-29 20:19:19 +02:00
e960626804 Add npupnp support
libnpupnp is a C++ modification of libupnp.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-03-26 14:14:58 -07:00
7dd2dce6ad Support new tags in proxy plugin
Add support for the following tags when using the proxy database plugin:
WORK
CONDUCTOR
LABEL
GROUPING
MUSICBRAINZ_WORKID
COMPOSERSORT
ENSEMBLE
MOVEMENT
MOVEMENTNUMBER
LOCATION
2021-03-24 20:59:54 +01:00
a7ba10423d Merge branch 'v0.22.x' 2021-03-13 08:41:10 +01:00
8f1e7385b7 Add tags relevant to classical music.
This commit adds some tags that are (mostly) interesting for listeners
of classical music.

Ensemble
--------
This is an ensemble that is playing the music, such as Wiener
Philharmoniker. The tag can be used to distinguish the ensemble from the
conductor, composer, soloist, and ensemble, that are generally all in
the "ARTIST" tag.

Movement
-------
The movement number and movement (name) of this track, i.e.  "II" and
"Allegro".

ComposerSort
------------
Allows us to look for Beethoven's 9th under B, for Beethoven, not L for
Ludwig.

Location
--------
This is the location of the recording, e.g. "Wiener Musikverein".
2021-03-10 21:24:25 +01:00
25354b9d8c Merge branch 'v0.22.x' 2021-03-10 21:06:12 +01:00
ee720064a7 Merge branch 'v0.22.x' 2021-03-05 19:41:17 +01:00
e1b62fb90d Merge branch 'v0.22.x' 2021-03-05 19:33:46 +01:00
422cf5f182 Merge branch 'v0.22.x' 2021-03-05 16:05:56 +01:00
ef1acb4e2f Merge branch 'v0.22.x' 2021-03-04 18:56:29 +01:00
d4bbb8c851 Merge branch 'struc' of git://github.com/neheb/MPD 2021-03-04 17:50:53 +01:00
428f769c38 output/pipewire: new output plugin
Very rough draft.  Barely works.
2021-03-03 18:44:39 +01:00
133c8834df output/httpd: update API documentation 2021-03-02 18:24:57 +01:00
99217593bf test/util/TestIntrusiveList: add AutoUnlink test 2021-03-02 18:15:37 +01:00
1c6e4a2b18 test/util/TestIntrusiveList: new unit test 2021-03-02 18:12:15 +01:00
a6eb264770 util/IntrusiveList: add type alias "Hook"
By casting to SafeLinkIntrusiveListHook if appropriate, this fixes a
bug in the erase() method, where erase() calls
IntrusiveListHook::unlink() instead of
SafeLinkIntrusiveListHook::unlink().
2021-03-02 17:51:50 +01:00
f5f296b13a event/TimerWheel: add a "ready" list as a special case
This reduces delays of zero-duration timers from up to 1 second to
zero.  libavahi-client schedules zero-duration timers often.
2021-03-02 17:14:33 +01:00
0091c4e12b util/Exception: add FindNested() 2021-03-02 17:13:29 +01:00
80172e17ac util/Exception: remove redundant std::exception catch clause
The "std::nested_exception" catch block already covers this perfectly.
2021-03-02 17:13:21 +01:00
2d96b05403 test/util/TestException: add CheckFindRetrowNested() unit test 2021-03-02 17:12:43 +01:00
ec0c1f0d02 util/Exception: fix comment typo 2021-03-02 17:12:20 +01:00
946b3c1f80 util/IntrusiveList: add method erase_and_dispose() 2021-02-25 14:12:47 +01:00
a0dc398f36 util/IntrusiveList: erase() returns an iterator 2021-02-25 14:12:39 +01:00
b54d2d984a util/IntrusiveList: use ToHook() in erase() 2021-02-25 14:12:10 +01:00
4ab73f9de9 util/IntrusiveList: add missing ToNode() cast in iterator_to() 2021-02-25 14:10:55 +01:00
5ebe23e4bb db/upnp/Discovery: use class IntrusiveList 2021-02-24 20:39:42 +01:00
aa227cded1 input/qobuz: use class IntrusiveList 2021-02-24 20:31:47 +01:00
e406bdbb80 input/tidal: use class IntrusiveList 2021-02-24 20:31:13 +01:00
1048f23680 util/IntrusiveList: add hook class SafeLinkIntrusiveListHook
Similar to boost::intrusive::safe_link.
2021-02-24 20:29:16 +01:00
8fe8f09027 util/IntrusiveList: add noexcept 2021-02-24 20:17:28 +01:00
78670c0941 util/IntrusiveList: add constexpr 2021-02-24 20:16:54 +01:00
34f735890e output/snapcast: remove obsolete TODO comment 2021-02-24 17:05:14 +01:00
f08810b202 output/snapcast: add missing #ifdef HAVE_ZEROCONF 2021-02-24 17:04:15 +01:00
7a68775e6c output/snapcast: Zeroconf support 2021-02-24 17:03:30 +01:00
e4fccc85c8 Main: move Zeroconf to the I/O thread
This will allow using Zeroconf in output plugins (preparing for
Snapcast with Zeroconf).
2021-02-24 16:29:33 +01:00
2efa142ec9 output/init: use the real-time I/O thread only for the ALSA plugin 2021-02-24 16:09:11 +01:00
29b49dd630 zeroconf/{bonjour,avahi}: pass service_type as parameter 2021-02-24 15:11:11 +01:00
9d6bf7e720 test/run_avahi: refactor to RunZeroconf (both avahi and bonjour) 2021-02-24 15:09:10 +01:00
5f34508aae zeroconf/Glue: move code to the ZeroconfHelper constructor 2021-02-24 15:09:10 +01:00
2d8ecd561b zeroconf: return a publisher object 2021-02-24 15:09:10 +01:00
2059195ae9 zeroconf: add dependency on event_dep 2021-02-24 15:09:10 +01:00
d89856f77b zeroconf/avahi/Helper: make class SharedAvahiClient final 2021-02-24 15:09:10 +01:00
975d5be046 zeroconf/avahi/Init: return a std::unique_ptr<AvahiHelper> 2021-02-24 14:41:37 +01:00
b01ef1b9a6 zeroconf/Bonjour: return a std::unique_ptr<BonjourHelper> 2021-02-24 14:25:06 +01:00
ceb76b6a82 zeroconf/Bonjour: pass a context pointer to the callback 2021-02-24 14:18:35 +01:00
a7e697b588 zeroconf/Bonjour: add const 2021-02-24 14:18:17 +01:00
3ecd918442 zeroconf/Bonjour: move the DNSServiceRegister() call to the constructor 2021-02-24 14:17:59 +01:00
4fbdb3a2d5 zeroconf/Bonjour: convert the callback function to a method 2021-02-24 14:15:26 +01:00
0157643667 zeroconf/Glue: add noexcept 2021-02-24 14:15:26 +01:00
fe741bd767 zeroconf/Glue: allow ZeroconfInit() to throw 2021-02-24 14:15:04 +01:00
06b9bdba2c zeroconf/Bonjour: disallow copying 2021-02-24 13:53:36 +01:00
bd0aa74bdd zeroconf/Bonjour: rename class BonjourMonitor to BonjourHelper 2021-02-24 13:53:35 +01:00
47461df59c zeroconf/Bonjour: don't call DNSServiceRefDeallocate() if DNSServiceRegister() fails
According to
https://developer.apple.com/documentation/dnssd/1804733-dnsserviceregister
the DNSServiceRef is initialized only if DNSServiceRegister() returns
kDNSServiceErr_NoError.  The faulty error handling code could
therefore crash.
2021-02-24 13:49:03 +01:00
04d5588fe5 zeroconf/Zeroconf*: drop prefix from file names 2021-02-24 13:33:59 +01:00
40d061621b zeroconf/Avahi: remove useless log messages 2021-02-24 13:33:58 +01:00
a312629aad zeroconf: pass global port to init function 2021-02-24 06:40:26 +01:00
d527d4b530 zeroconf/avahi/Publisher: new class, replacing lots of code from ZeroconfAvahi.cxx 2021-02-23 22:07:57 +01:00
978d2638d8 zeroconf/avahi/Client: new class, replacing lots of code from ZeroconfAvahi.cxx 2021-02-23 21:53:07 +01:00
cfcafdf822 zeroconf/avahi: add class AvahiGlue 2021-02-23 21:53:00 +01:00
07865d0707 zeroconf/avahi/Poll: move to namespace Avahi 2021-02-23 21:41:16 +01:00
1ac16516a1 event/TimerList: add option to avoid the Boost dependency 2021-02-22 23:35:16 +01:00
75e8795e3f util/IntrusiveList: add method insert() 2021-02-22 23:32:51 +01:00
4912466d50 util/IntrusiveList: add method erase() 2021-02-22 23:32:47 +01:00
664674913e event/Loop: include cleanup 2021-02-22 23:32:39 +01:00
31e3658823 Merge branch 'v0.22.x' 2021-02-22 23:25:07 +01:00
abd416735d output/snapcast: implement SendTag() 2021-02-22 23:20:56 +01:00
6090bd2095 lib/yajl/Gen: new class 2021-02-22 23:12:08 +01:00
1777592ec0 lib/yajl/Handle: fix API documentation 2021-02-22 22:56:52 +01:00
8e8fbe14b1 output/snapcast: implement Drain() 2021-02-22 22:49:32 +01:00
a8a39b6a38 output/snapcast: queue chunks 2021-02-22 22:41:31 +01:00
f84cb6de5e output/snapcast/client: remove obsolete TODO comment
See commit dfc67c45c7
2021-02-22 22:39:32 +01:00
dfc67c45c7 output/snapcast: calculate the latency for TIME responses 2021-02-22 21:57:20 +01:00
e875da5d38 output/snapcast/protocol: swap "received" and "sent"
Snapcast's protocol documentation is wrong, see
https://github.com/badaix/snapcast/pull/811
2021-02-22 21:42:42 +01:00
9b9522e3f5 zeroconf/avahi/Poll: rename internal variables 2021-02-22 15:01:01 +01:00
87963685fb zeroconf/avahi/Poll: use C++11 initializer 2021-02-22 15:00:20 +01:00
0405a57f26 zeroconf/avahi/Poll: make EventLoop the first parameter 2021-02-22 14:52:21 +01:00
f29c69d6a9 zeroconf/avahi/Poll: rename timer to event 2021-02-22 14:39:28 +01:00
7ec4de841e zeroconf/avahi/Poll: add constexpr 2021-02-22 14:34:32 +01:00
1f08d2d03c zeroconf/avahi/Poll: add noexcept 2021-02-22 14:31:37 +01:00
c1a695d1ac zeroconf/avahi/Poll: add method GetEventLoop() 2021-02-22 14:31:10 +01:00
ec05056e38 zeroconf/avahi/Poll: forbid copying 2021-02-22 14:26:08 +01:00
c0b9339d31 zeroconf/AvahiPoll: move to lib/avahi/ 2021-02-22 14:24:00 +01:00
00a1731085 Merge branch 'timeout_in_second' of git://github.com/mxjeff/MPD 2021-02-20 20:11:38 +01:00
6e3da00874 MPD_TIMEOUT is in seconds
At least I believe libmpdclient is reading env. var. as second:
https://github.com/MusicPlayerDaemon/libmpdclient/blob/master/src/settings.c#L142

ncmpc manual also mentions MPD_TIMEOUT being is second.
2021-02-20 15:22:18 +01:00
38df01b266 Add password use with MPD_HOST 2021-02-20 15:21:15 +01:00
c729f16dcd song/DetachedSong: copy the AudioFormat from LightSong
Enables the "Format" row in "playlistinfo" responses.

https://github.com/MusicPlayerDaemon/MPD/issues/1094
2021-02-18 22:16:11 +01:00
81d0c04ed4 song/DetachedSong: add noexcept 2021-02-18 22:01:52 +01:00
0924b63e10 event/TimerWheel: add empty flag to optimize a common case 2021-02-17 19:52:45 +01:00
ce6afe9379 output/httpd/Page: convert to type alias on AllocatedArray 2021-02-17 18:01:27 +01:00
6f04b2230a output/httpd/Page: use std::byte 2021-02-17 17:54:38 +01:00
8d90b831e1 output/snapcast/Timestamp: drop static 2021-02-17 14:39:20 +01:00
d4710604c4 doc/plugins.rst: fix typo 2021-02-17 14:39:06 +01:00
9c8da03c5c output/snapcast: new output plugin
New experimental code, first draft - it works, but there's a lot left
to do.  Just look at all the TODO comments.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/975
2021-02-17 14:25:23 +01:00
85adefd9a4 encoder/wave: remove constexpr because memcpy() is not allowed 2021-02-17 14:19:02 +01:00
22804cfbe8 Merge branch 'patch-2' of git://github.com/fschlich/MPD 2021-02-17 07:25:06 +01:00
8a4b88a59d encoder/wave: use the structs from RiffFormat.hxx 2021-02-16 19:50:52 +01:00
d2371af120 encoder/wave: add static_assert on sizeof(WaveHeader) 2021-02-16 19:50:46 +01:00
aa2e1bb310 encoder/wave: refactor fill_wave_header() to function 2021-02-16 19:50:43 +01:00
6153fca4fc tag/RiffFormat: add struct RiffFmtChunk 2021-02-16 19:50:40 +01:00
f090af0a22 tag/RiffFormat: add static_asserts on sizeof() 2021-02-16 19:50:25 +01:00
58f420fdca tag/RiffFormat: use CamelCase 2021-02-16 19:24:51 +01:00
ded2b31fbc tag/Riff: split into RiffId3.?xx and RiffFormat.hxx 2021-02-16 19:23:01 +01:00
75c8d2235b util/ByteOrder: add classes PackedBE16, PackedLE16, PackedLE32 2021-02-16 17:37:25 +01:00
f679961564 Merge tag 'v0.22.6'
release v0.22.6
2021-02-16 13:58:47 +01:00
471c37be59 queue/PlaylistEdit: convert start/end parameters to RangeArg 2021-02-15 22:51:09 +01:00
157ddcbab1 protocol/RangeArg: add methods ClipRelaxed(), CheckClip(), CheckAdjustEnd() 2021-02-15 22:50:49 +01:00
ab160aa359 queue/PlaylistEdit: check "current>=0" before updating it 2021-02-15 22:50:37 +01:00
ecc07e4e98 Merge tag 'v0.22.5'
release v0.22.5
2021-02-15 22:50:16 +01:00
cbc830fd65 doc/client.rst: fix typo 2021-02-15 20:23:32 +02:00
98a9f81d61 doc/client.rst: new chapter about client development 2021-02-15 13:26:25 +01:00
f5460b35a3 Add cacert option for Curl plugin. Allows to set cacert for curl lib ()
Add cacert option for curl plugin

    add cacert option for Curl plugin. Allows to set cacert for curl lib
    Added documentation line into doc/plugins.rst with explanation for cacert option
2021-02-13 13:49:15 +02:00
3456b1e50d use std::size_t 2021-02-12 18:39:28 +01:00
fe6abe1750 zlib/Error: add noexcept 2021-02-12 18:37:32 +01:00
6cdb3ff21e use [[gnu::pure]] instead of gcc_pure
This is semi-standard and doesn't require the util/Compiler.h header.
2021-02-12 18:34:16 +01:00
01af2778ab time/ISO8601: throw std::invalid_argument on error
Throwing std::runtime_error was slightly wrong.
2021-02-12 18:31:56 +01:00
ad03c70753 event/TimerWheel: workaround for GCC9 bug 2021-02-12 18:29:02 +01:00
7fe0095fa7 util/IntrusiveList: add noexcept to defaulted constructor 2021-02-11 21:22:15 +01:00
a4b236348f Merge branch 'v0.22.x' 2021-02-07 22:04:07 +01:00
aa40aae5bd doc/user.rst: add section about profiling MPD 2021-02-07 21:38:24 +01:00
5a16e3ffa3 event/TimerWheel: optimized container for CoarseTimerEvent 2021-02-05 18:24:25 +01:00
d1957b83c8 event/Chrono: add type alias TimePoint 2021-02-05 18:19:23 +01:00
1b4fd74575 event/TimerEvent: rename to FineTimerEvent
... and make TimerEvent a type alias for FineTimerEvent (i.e. swap
names).
2021-02-05 18:18:05 +01:00
def962b6cb event/{Coarse,Fine,Far}TimerEvent: aliases for TimerEvent
Preparing for a variant of TimerEvent with coarse 1-second
granularity, but cheaper (with a timer wheel).
2021-02-05 18:16:05 +01:00
e802f1f61a event/Loop: move TimerSet to separate class 2021-02-05 18:09:21 +01:00
271b287356 event/TimerEvent: assign due in Schedule() 2021-02-05 17:57:05 +01:00
2a30acd99c event/Loop: use [[gnu::pure]] 2021-02-05 17:55:33 +01:00
a8e70f18fd event/*: use using instead of typedef 2021-02-05 17:54:16 +01:00
ddd9f20a0b fs/io/GunzipReader: document that the constructor throws 2021-02-04 17:29:00 +01:00
f4a5d671fe util/{Const,Writable}Buffer: include cleanup 2021-02-04 17:27:48 +01:00
c72006dbcc zeroconf/ZeroconfBonjour: Cleanup formatting from previous commit 2021-01-23 06:13:05 -05:00
06fe30e2bd zeroconf/ZeroconfBonjour: Fix compile errors resulting from "refactor to SocketEvent" and reenable bonjour for darwin build 2021-01-23 06:06:49 -05:00
08e76815ba io/FileDescriptor: use std::byte 2021-01-22 12:50:16 +01:00
33ac3eb551 lib/curl/Easy: add methods SetVerify{Host,Peer}() 2021-01-22 12:34:04 +01:00
d56a51cb5e Merge branch 'v0.22.x' 2021-01-21 22:28:11 +01:00
065a0c09f8 fs/io/StdioOutputStream: include cleanup 2021-01-21 21:13:40 +01:00
04731fb7cc util/StringPointer: add operator==(std::nullptr_t) 2021-01-21 21:08:52 +01:00
12ff5a547f fs/io/FileOutputStream: add noexcept 2021-01-21 21:04:19 +01:00
9b2eb74f95 util/AllocatedString: fix operator= parameter type 2021-01-21 20:44:07 +01:00
84084baa65 util/AllocatedString: remove wrong std:: prefix 2021-01-21 20:16:32 +01:00
3bc45fbf68 util/AllocatedString: remove Null(), IsNull() 2021-01-21 20:12:05 +01:00
36168a24f5 util/AllocatedString: support casting a nulled instance to string_view 2021-01-21 20:06:01 +01:00
5e67443a1a util/{Const,Writable}Buffer: always enable assertions 2021-01-21 20:04:00 +01:00
17858143b3 util/{Const,Writable}Buffer: enable constexpr on more methods 2021-01-21 20:03:53 +01:00
c44a7b2705 util/AllocatedArray: add operator=(nullptr) 2021-01-21 20:03:38 +01:00
0ded23591b util/AllocatedString: add operator=() 2021-01-21 20:02:52 +01:00
c1a7aa652d util/AllocatedString: replace Clone() with copy constructor 2021-01-21 20:02:41 +01:00
8d47f51399 util/AllocatedString: add const_pointer constructor 2021-01-21 18:06:10 +01:00
a81c9bfb81 util/AllocatedString: add string_view constructor
Replaces the static Duplicate() method.
2021-01-21 18:05:51 +01:00
1caf57644f util/AllocatedString: add default constructor 2021-01-21 18:05:50 +01:00
c70b63c183 util/AllocatedString: rename to BasicAllocatedString
To make things simpler, AllocatedString is now a non-template class.
2021-01-21 18:04:03 +01:00
1b89b4ef83 Merge branch 'v0.22.x' 2021-01-21 17:45:15 +01:00
8279cafd6d Merge tag 'v0.22.4'
release v0.22.4
2021-01-21 17:42:26 +01:00
014c2a82bd event/SignalMonitor: fix non-Linux build failure
Regression by commit cd4b673b6c

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1060
2021-01-21 14:05:23 +01:00
594dfe572b clang-tidy: mark a bunch of variables constexpr
Found with cppcoreguidelines-interfaces-global-init

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-01-16 18:35:31 -08:00
906e82f600 event/Loop: fix assertion failure due to wrong "busy" value
If an InjectEvent callback schedules a timer, the loop will restart,
but the "busy" flag is still false.  The fix is to move the "again"
check before the "busy" setting.
2021-01-12 17:28:42 +01:00
bcb7e954e9 net/Resolver: add simple getaddrinfo() wrapper 2021-01-12 15:43:26 +01:00
866c87c65e net/ToString: include cleanup 2021-01-12 12:22:44 +01:00
4ba36d7cb9 net/SocketError: relicense to BSD-2 2021-01-11 22:31:46 +01:00
13f8a912e3 event/Loop: simplify wake_event initializer 2021-01-11 20:14:20 +01:00
51f110a990 system/EventPipe: use class Unique{Socket,File}Descriptor 2021-01-11 17:51:22 +01:00
17eae74c1c system/EventFD: Get() returns FileDescriptor 2021-01-11 17:38:30 +01:00
cd4b673b6c event/WakeFD: convert macro to class with a GetSocket() method 2021-01-11 17:02:54 +01:00
0d606c743b add additional opus encoder options 2021-01-09 22:04:00 -06:00
81ea749248 Merge branch 'v0.22.x' 2021-01-05 13:11:29 +01:00
e009ad1a72 thread/Id: relicense to BSD-2 2021-01-03 19:25:20 +01:00
abbd980671 Merge branch 'v0.22.x' 2021-01-01 19:59:15 +01:00
937da63ba6 util/StringView: add {Starts,Ends}With(char) 2020-12-15 17:04:39 +01:00
1f312b2e42 curl/Handler: disallow OnData() to throw
This eliminates some complexity from class CurlRequest.
2020-12-15 17:03:24 +01:00
1e3089ffb7 curl/Request: move struct Pause to class CurlResponseHandler 2020-12-15 17:01:18 +01:00
5d7ff150dd curl/Request: add more wrapper methods 2020-12-15 16:56:20 +01:00
c767501c12 Merge branch 'v0.22.x' 2020-12-15 14:11:06 +01:00
00602d28a4 doc/protocol.rst: ensure all commands have targets 2020-12-15 13:49:57 +01:00
7a56837141 odbus/Watch: support DBUS_WATCH_{ERROR,HANGUP} 2020-12-14 15:10:19 +01:00
ed1caffc79 odbus/Watch: use SocketEvent::ReleaseSocket() to allow another Open() 2020-12-14 15:10:15 +01:00
65473b5113 lib/dbus/FilterHelper: new class 2020-12-14 15:07:12 +01:00
178d115ccb lib/dbus/Glue: add noexcept 2020-12-14 13:19:51 +01:00
10e5b0759c lib/dbus/Glue: relicense to BSD-2 2020-12-14 13:02:37 +01:00
0a81e462db event/SocketEvent: remove FD before closing socket
SocketEvent knows the FD is still open and is about to close it, so
it's unnecessary to rely on the kernel (via AbandonFD) to clean up the
epoll_wait list.

### Why this is relevant

- `AbandonFD` assumes that upon closing the socket, the FD will be automatically removed from the epoll list. That fd is associated with a reference to the `SocketEvent`, so this is an important and dangerous assumption to get wrong. In the case that the FD isn't immediately removed from the list by the kernel, the event loop can crash due to the `SocketEvent` being destroyed and it being a use-after-free bug at that point.
- If a socket FD happens to be duplicated, then closing the SocketEvent FD will not automatically remove it from epoll, and will trigger said bug/crash. It is only automatically removed when all FD references to the underlying socket/resource are closed?
- A `fork()` is one example where a socket FD can be duplicated and result in this situation.
    - `CLOEXEC` might be considered mitigation for this but also introduces a race condition where the crash can occur between a `fork()` and `exec()` without additional synchronization to freeze the event loop.

One could argue the mpd event loop isn't fork-safe, and thus should be allowed to use `AbandonFD` however it likes. A decision on whether this is intended should probably be declared; but either way this fix seems appropriate in cases where `Abandon` isn't actually necessary. It also might be possible to fix `AbandonFD` to mark the `SocketEvent` as removed without using `EPOLL_CTL_DEL`?

[edit: made this dependent on HAVE_THREADED_EVENT_LOOP which is always
true for MPD, but not for ncmpc, for example - mk]
2020-12-04 10:32:46 +01:00
5cbbe8ae2e event/TimerEvent: update API documentation 2020-12-04 09:57:19 +01:00
00fafa16c7 event/SocketEvent: remove assert(), reduce header dependencies 2020-12-04 09:56:28 +01:00
cea8db7eaa event/SocketEvent: add comment 2020-12-04 09:55:08 +01:00
b56c0e69e4 event/SocketEvent: add another assert() to Open() 2020-12-04 09:24:02 +01:00
b27e82e4a9 event/SocketEvent: allow Schedule() with IMPLICIT_FLAGS
Relax the API (instead of tightening it further like commit
7bc1c9925b tried to do unsuccessfully).
2020-12-04 09:17:45 +01:00
ad48834469 Revert "event/SocketEvent: add assert()"
This reverts commit 7bc1c9925b.  It
caused a crash with the ALSA plugin family (through
MultiSocketMonitor::ReplaceSocketList() and
MultiSocketMonitor::AddSocket()).  Until we have a proper fix, the
assertion patch is reverted.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1020
2020-12-02 20:43:29 +01:00
9d6b5e2ba1 event/TimerEvent: rename IsActive() to IsPending() 2020-12-02 15:41:11 +01:00
33ba190bec event/TimerEvent: add ScheduleEarlier() 2020-12-02 15:30:37 +01:00
3783350d25 event/SocketEvent: document Dispatch() 2020-12-02 15:24:23 +01:00
173405a343 event/SocketEvent: make Dispatch() private 2020-12-02 15:14:51 +01:00
7bc1c9925b event/SocketEvent: add assert() 2020-12-02 15:12:30 +01:00
ce4c69dd95 test/util/TestException: new unit test 2020-12-02 15:09:47 +01:00
8eea825462 test/util/TestTemplateString: new unit test 2020-12-02 15:03:51 +01:00
49e1ce7c43 test/TestUtil: move to test/util/ 2020-12-02 15:02:45 +01:00
618f94f589 util/TemplateString: add StringView cast operator 2020-12-02 15:00:49 +01:00
ad2c22844c util/TemplateString: add FromLiteral() 2020-12-02 15:00:39 +01:00
b8df851414 io/FileDescriptor: use std::size_t 2020-12-02 14:56:00 +01:00
a584141cae io/Open: add flags parameter to OpenReadOnly() 2020-12-02 14:52:51 +01:00
4e88f95f94 event/Loop: move the "again" check out of the mutex scope 2020-12-01 20:29:21 +01:00
790e540c19 event/Loop: use ClockCache 2020-12-01 20:25:42 +01:00
16074c565f time/ClockCache: new library 2020-12-01 20:22:26 +01:00
2a1dd55b11 event/Loop: include cleanup 2020-12-01 20:19:40 +01:00
be20f760ab event/Loop: disallow copying 2020-12-01 20:18:33 +01:00
8050394003 event/Loop: add noexcept 2020-12-01 20:10:53 +01:00
ff8b5bc61b event/Loop: reorder methods 2020-12-01 20:09:25 +01:00
ef8797821f event/Loop: inline field initializers 2020-12-01 20:07:35 +01:00
5f2797e7cc event/Loop: add more assertions to dtor 2020-12-01 20:05:54 +01:00
e286702f4c event/Loop: rename AddDeferred() to AddDefer() 2020-12-01 17:26:39 +01:00
c58aaf545f event/IdleEvent: make a special case of DeferEvent 2020-12-01 17:14:24 +01:00
990f2dc1cf event/DeferEvent: use class IntrusiveList instead of boost::intrusive::list 2020-12-01 17:14:24 +01:00
774b4313f2 event/DeferEvent: split the thread-safe version into new class InjectEvent 2020-12-01 17:14:24 +01:00
1ecbc2ff0f event/DeferEvent: explicitly forbid copying 2020-12-01 17:14:24 +01:00
fd8e38f8cd event/DeferEvent: use using instead of typedef 2020-12-01 17:14:24 +01:00
e86d4db55c Merge branch 'v0.22.x' 2020-12-01 17:14:21 +01:00
9420c74101 util/AllocatedArray: add nullptr constructor 2020-11-30 22:30:57 +01:00
b1bef9c21d util/AllocatedArray: add method data() 2020-11-30 22:30:28 +01:00
5b0ef7ea98 util/AllocatedArray: add types pointer, const_pointer 2020-11-30 22:30:25 +01:00
ab53c414bc util/StringView: add method SplitLast() 2020-11-30 22:29:38 +01:00
d547ace749 io/FileDescriptor: use std::size_t 2020-11-30 22:27:16 +01:00
b47e0cffdd util/TemplateString: rename CharAsString() to FromChar() 2020-11-30 22:23:28 +01:00
3af35aee9e util/TemplateString: add cast operators 2020-11-30 22:22:24 +01:00
02314ac7dd util/TemplateString: rewrite as constexpr functions
Hooray C++17!
2020-11-30 22:19:57 +01:00
e7c4e87ac4 util/TemplateString: remove unnecessary implementation for static variable
This is obsolete since C++17.
2020-11-30 22:13:13 +01:00
de58bfbb7f util/TemplateString: use std::size_t 2020-11-30 22:13:08 +01:00
0dda4c06b1 util/TemplateString: no indent after namespace 2020-11-30 22:13:04 +01:00
79fd6143ec lib/dbus/Values: use T::Traits, not T
This template was never instantiated, so the problem never occurred.
2020-11-30 22:11:18 +01:00
8f89e3f7f4 lib/dbus/Values: use using instead of typedef 2020-11-30 22:11:14 +01:00
fc01d11b8d odbus/Types: use using instead of typedef 2020-11-30 22:08:37 +01:00
0c28d8dcbe time/ISO8601: support YYYY-MM (without day of month) 2020-11-30 21:55:12 +01:00
764eaadd25 time/Math: new library 2020-11-30 21:55:05 +01:00
273771ffec net/SocketAddress: add CastTo() 2020-11-30 21:51:07 +01:00
32ce9ce919 net/IPv[46]Address: pass SocketAddress by value to Cast() 2020-11-30 21:49:07 +01:00
34a070f5a6 net/IPv[46]Address: add Cast(const sockaddr_in&) 2020-11-30 21:49:02 +01:00
ac4975cd7a util/MimeType: relicense to BSD-2 2020-11-18 15:28:21 +01:00
fbbbfb9668 Merge branch 'v0.22.x' 2020-11-16 09:41:20 +01:00
eb9f5339b6 Merge branch 'v0.22.x' into master 2020-11-11 12:43:50 +01:00
a9714e73c8 Merge branch 'bind' of git://github.com/neheb/MPD into master 2020-11-10 16:02:34 +01:00
a99bc91eb0 Merge tag 'v0.22.3' into master
release v0.22.3
2020-11-06 16:14:46 +01:00
071d3c71d8 clang-tidy: replace std::bind with lambdas
Found with modernize-avoid-bind

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-11-05 18:09:30 -08:00
afbcac9fb1 util/MimeType: use IterableSplitString() in ParseMimeTypeParameters() 2020-11-04 21:29:42 +01:00
51e5b56b3a playlist/registry: remove duplicate function ExtractMimeTypeMainPart()
This is the same as GetMimeTypeBase(), which has already been applied.
2020-11-04 21:20:43 +01:00
bb07fd42ce util/MimeType: migrate GetMimeTypeBase() to std::string_view 2020-11-04 21:20:03 +01:00
bab626c325 util/UriExtract: remove the query string at the beginning of uri_get_suffix() 2020-11-04 21:15:41 +01:00
2a9131498f util/UriExtract: pass std::string_view to uri_get_suffix() 2020-11-04 21:13:57 +01:00
35a232105e util/UriExtract: uri_get_suffix() returns std::string_view
No need to copy it to a buffer.
2020-11-04 21:08:26 +01:00
19dd1a25d7 {decoder,archive,playlist}/plugin: pass std::string_view to SupportsMimeType() 2020-11-04 21:00:49 +01:00
53396c0e50 Merge branch 'v0.22.x' into master 2020-11-04 20:37:25 +01:00
0b8208fe7f Merge branch 'clng11' of git://github.com/neheb/MPD into master 2020-11-04 20:34:55 +01:00
3d276d50b4 event/PollBackend: use vector::push_back() instead of resize() 2020-10-30 16:35:20 +01:00
b1b731340e event/PollBackend: add Item constructor 2020-10-30 16:32:45 +01:00
b9b02b4ff2 event/PollBackend: use unordered_map::find() instead of operator[]
The latter creates a new object, but we know that the key already
exists.
2020-10-30 16:25:41 +01:00
ab5d23da11 event/PollBackend: use unordered_map::emplace() in Add() 2020-10-30 16:24:32 +01:00
0554fe3652 event/PollBackend: use std::size_t 2020-10-30 16:09:29 +01:00
b0282fe36f event/PollGroupWinSelect: add Item constructor 2020-10-30 16:07:23 +01:00
69b45e693b event/WinSelect: use unordered_map::find() instead of operator[]
The latter creates a new object, but we know that the key already
exists.
2020-10-30 16:05:25 +01:00
9e97acc28d event/WinSelect: merge duplicate code into ApplyReady() 2020-10-30 15:55:23 +01:00
b1e446a931 event/WinSelect: add missing const to deleted copy ctor/operator 2020-10-30 15:45:29 +01:00
938319cd44 event/WinSelect: reorder method prototypes 2020-10-30 15:45:12 +01:00
fee29001fa event/WinSelect: use unordered_map::emplace() in Add()
This allow using erase() with iterator, without a key lookup.
2020-10-30 15:32:11 +01:00
6d894a1806 event/WinSelect: use SOCKET as std::unordered_map key 2020-10-30 15:25:09 +01:00
f1fc5d79ca clang-tidy: convert to all/any_of
Found with readability-use-anyofallof

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-28 15:51:21 -07:00
0fd2c74a66 use structured binding declarations
Shorter.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-28 15:41:31 -07:00
bb99cf37e3 Merge tag 'v0.22.2' into master
release v0.22.2
2020-10-28 17:33:10 +01:00
7c47fe746c event/Loop: AbandonFD() unlinks the SocketEvent
Fixes use-after-free bugs causing assertion failures at shutdown,
because all "abandoned" SocketEvents are still in the linked list.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/986
Closes https://github.com/MusicPlayerDaemon/MPD/issues/987
2020-10-28 15:01:32 +01:00
65a1c4a016 event/Loop: pass SocketEvent& to AbandonFD() 2020-10-28 14:59:28 +01:00
46418d0f2d event/ServerSocket: remove obsolete API documentation 2020-10-28 14:52:31 +01:00
ad585e179f system/FileDescriptor: fix Duplicate result
dup2 returns new_fd on success, not 0
2020-10-20 09:32:43 -07:00
8348a1ec8f event/PollGroup: rename to PollBackend 2020-10-19 14:52:59 +02:00
c18e00daa4 event/PollGroup: move event flags to a separate header
Reduce header dependencies for SocketEvent.hxx.
2020-10-19 14:48:41 +02:00
418ba96334 event/SocketEvent: forbid copying 2020-10-18 20:07:49 +02:00
a60e782959 event/Loop: reorder assertions 2020-10-18 20:05:22 +02:00
8bab5733d7 event/Loop: add assertions 2020-10-18 20:04:16 +02:00
e3270dfd68 event/SocketEvent: use class IntrusiveList<> 2020-10-18 20:02:47 +02:00
a14997ffb8 event/Loop: manage all SocketEvents in a linked list
Not only those which are "ready".
2020-10-18 20:01:38 +02:00
dd94f97572 event/Loop: un-inline AddFD(), ModifyFD()
Prepare for adding more code here.
2020-10-18 19:58:42 +02:00
7d502fb448 event/Loop: round epoll_wait() timeout up
This implements proper rounding, amending commit dcbb9fe07c
2020-10-18 19:58:42 +02:00
3ac87bbcda io/uring/Queue: use IntrusiveList<> 2020-10-18 19:37:54 +02:00
f64799622d event/IdleEvent: use class IntrusiveList<> 2020-10-18 19:28:12 +02:00
6f0ad2b6c5 util/IntrusiveList: replacement for boost::intrusive::list 2020-10-18 19:23:34 +02:00
b5750afb24 event/IdleEvent: use auto 2020-10-18 19:23:34 +02:00
442dd5e955 event/IdleEvent: forbid copying 2020-10-18 19:23:25 +02:00
172c2ae1aa Merge tag 'v0.22.1' into master
release v0.22.1
2020-10-17 13:58:36 +02:00
4f0e0af319 Merge branch 'v0.22.x' into master 2020-10-16 19:02:03 +02:00
cb382b1e7d event/PollGroupWinSelect: add missing return value
Fixes regression from commit 1473d8474f
2020-10-16 19:02:00 +02:00
871bf3b88f command: add command "getvol"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/979
2020-10-16 17:51:51 +02:00
08360e401d meson.build: increment protocol version to 0.23 2020-10-16 17:46:47 +02:00
b611b1824a event/Loop: move code to Wait() 2020-10-15 20:21:00 +02:00
1473d8474f event/PollGroup: ReadEvents() returns PollResult 2020-10-15 20:15:09 +02:00
0ecc3394c3 Merge branch 'v0.22.x' into master 2020-10-15 20:14:36 +02:00
725985379a event/SocketEvent: add ScheduleImplicit(), Is{Read,Write}Pending() 2020-10-15 17:01:30 +02:00
8849b9b62c event/SocketEvent: move Abandon() up 2020-10-15 16:59:45 +02:00
caa2611ad5 event/SocketEvent: add Abandon() 2020-10-15 16:57:55 +02:00
f8ff597963 event/SocketEvent: document Close() 2020-10-15 16:55:31 +02:00
ff6e434caf event/SocketEvent: rename Steal() to ReleaseSocket() 2020-10-15 16:54:33 +02:00
95bb12880d net/UniqueSocketDescriptor: add noexcept 2020-10-15 16:46:29 +02:00
257196664a net/SocketAddress: add missing include 2020-10-15 16:45:50 +02:00
643bf95366 util/OffsetPointer: use std::ptrdiff_t 2020-10-15 16:41:39 +02:00
36a187da39 util/Cast: include cleanup 2020-10-15 16:40:26 +02:00
fec80f2835 util/Cast: use std::ptrdiff_t 2020-10-15 16:40:18 +02:00
4e47653cf6 lib/curl/Global: ignore curl_multi_socket_action() errors
Keep the logging library out of this low-level libcurl wrapper.
2020-10-15 16:31:31 +02:00
c13004f985 lib/curl/Multi: add Add(), Remove(), ... 2020-10-15 16:25:57 +02:00
baba41e304 lib/curl/Global: adjust parameter name 2020-10-15 16:16:02 +02:00
d87e09a8b4 lib/dbus/ReadIter: remove obsolete GCC warning workaround
We need at least GCC 8 anyway.
2020-10-15 16:08:29 +02:00
33146ac353 lib/dbus/Watch: adjust parameter name 2020-10-15 16:06:19 +02:00
bb20af8f20 util/StringStrip: use std::strlen() 2020-10-15 12:54:47 +02:00
9355ec44e0 util/StringStrip: use std::size_t 2020-10-15 12:53:02 +02:00
c63bd323ce util/StringCompare: use std::memcmp() 2020-10-15 12:48:33 +02:00
55db7105c5 event/SocketEvent: check/clear scheduled_flags in Close()
Fixes regression by commit 521e573be9
2020-10-14 21:08:39 +02:00
1c079e554b io/UniqueFileDescriptor: add method Release() 2020-10-14 20:50:02 +02:00
48afb68f3a event/SocketEvent: remove assert() from GetScheduledFlags()
Fixes regression by commit 7901b04c78
2020-10-14 20:50:02 +02:00
21f409d5e2 event/SocketEvent: fix grammar 2020-10-14 16:30:38 +02:00
521e573be9 event/SocketEvent: use EventLoop::AbandonFD() in Close() 2020-10-14 16:29:49 +02:00
abf9ae2dd9 event/Loop: rename Abandon() to AbandonFD() 2020-10-14 16:26:06 +02:00
9f013f7de4 event/SocketEvent: allow Close() without socket 2020-10-14 16:26:01 +02:00
7fc04fd5cd event/SocketEvent: move Dispatch() down 2020-10-14 16:21:41 +02:00
7901b04c78 event/SocketEvent: allow Cancel() without socket 2020-10-14 16:20:43 +02:00
653eea5840 event/SocketEvent: remove unnecessary initializer 2020-10-14 16:18:39 +02:00
5a4055fb08 event/SocketMonitor: refactor to SocketEvent
Similar to commits 1686f4e857 and
30a5dd267b
2020-10-14 15:54:12 +02:00
4d68a12f03 event/Loop: split the AtScopeExit()
Fixes the !HAVE_THREADED_EVENT_LOOP build.
2020-10-14 14:47:59 +02:00
0e951da64b event/Loop: add missing #ifdef 2020-10-14 14:37:29 +02:00
38dab040b3 event/Loop: add compile-time option to disable multithreading
Not for MPD, but for other applications which might want to copy its
event loop, but do not need multi-threading.
2020-10-14 14:08:38 +02:00
e9f6af61f9 event/Loop: forward-declare class {Idle,Defer}Event 2020-10-14 14:05:17 +02:00
b06c4e2711 event/{Idle,Defer}Event: use base_hook instead of member_hook
Allows forward declaration.
2020-10-14 14:04:30 +02:00
1686f4e857 event/IdleMonitor: refactor to IdleEvent
Instead of using this as a base class implementing a virtual method,
the new class IdleEvent can be used as a variable, decoupling
IdleMonitor's internal state from the derived class.

This is similar to commit 30a5dd267b
which refactored TimeoutMonitor to TimerEvent.
2020-10-14 13:47:25 +02:00
9f57732af2 meson.build: increment version to 0.23~git
The new stable branch v0.22.x was forked off and is feature-frozen, so
the "master" branch will become the next major version eventually.
2020-10-14 12:13:12 +02:00
329382c1da event/SignalMonitor: add noexcept 2020-10-13 17:26:33 +02:00
fadc03df21 meson.build: move macros to event/Features.h 2020-10-13 16:15:52 +02:00
54ee0e28ab event/PollGroup: check _WIN32 instead of USE_WINSELECT 2020-10-13 15:27:58 +02:00
92fc53ebef event/PollGroupWinSelect: use range-based for 2020-10-12 12:44:23 +02:00
7e7a1613cf event/PollGroupWinSelect: use std::copy_n() 2020-10-12 12:40:32 +02:00
f73c4643ef event/PollGroupWinSelect: move IsEmpty() check to GetPtr() 2020-10-12 12:39:10 +02:00
8b94e8f260 event/PollGroupWinSelect: use SOCKET instead of int 2020-10-12 12:13:46 +02:00
41bc17a27f event/SocketMonitor: add ready_flags
By making each SocketMonitor keep track of its ready flags, this
removes a lot of overhead from EventLoop::RemoveFD().
2020-10-09 17:28:11 +02:00
936 changed files with 20284 additions and 10818 deletions
.github
.travis.ymlNEWSREADME.md
android
doc
meson.buildmeson_options.txt
python/build
src
CommandLine.cxxCommandLine.hxxIdleFlags.cxxIdleFlags.hxxInstance.cxxInstance.hxxListen.cxxLocateUri.cxxLog.cxxLog.hxxLogBackend.cxxLogInit.cxxMain.cxxMain.hxxMapper.cxxMapper.hxxMusicBuffer.cxxMusicBuffer.hxxMusicChunk.hxxMusicPipe.cxxMusicPipe.hxxPartition.cxxPartition.hxxPermission.cxxPermission.hxxPlaylistDatabase.cxxPlaylistDatabase.hxxPlaylistFile.cxxPlaylistFile.hxxPlaylistPrint.cxxPlaylistPrint.hxxPlaylistSave.cxxRemoteTagCache.cxxRemoteTagCache.hxxReplayGainInfo.hxxReplayGainMode.cxxReplayGainMode.hxxSingleMode.cxxSingleMode.hxxSongLoader.hxxSongPrint.cxxSongSave.cxxSongSave.hxxSongUpdate.cxxStateFile.cxxStateFile.hxxStateFileConfig.cxxStats.cxxTagAny.cxxTagPrint.cxxTagSave.cxxTagStream.cxxTimePrint.cxx
android
apple
archive
client
command
config
db
decoder
encoder
event
filter
fs
input
io
java
lib
alsa
cdio
crypto
curl
dbus
expat
ffmpeg
fmt
gcrypt
icu
nfs
pcre
pipewire
pulse
smbclient
sqlite
systemd
upnp
xiph
yajl
zlib
ls.cxxls.hxx
mixer
neighbor
net
output
pcm
player
playlist
protocol
queue
song
sticker
storage
system
tag
thread
time
unix
util
win32
zeroconf
subprojects
systemd
test
win32

12
.github/FUNDING.yml vendored

@ -1,12 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: MaxK
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

@ -18,5 +18,9 @@ about: Create a bug report
<!-- Paste the output of "mpd --version" here -->
## Configuration
<!-- Paste your MPD configuration here -->
## Log
<!-- Paste relevant portions of the log file here (--verbose) -->

@ -1,9 +0,0 @@
---
name: Question
about: Ask a question about MPD
---
<!-- Before you ask a question on GitHub, please read MPD's
documentation. A copy is available at
https://www.musicpd.org/doc/html/ -->
## Question

155
.github/workflows/build.yml vendored Normal file

@ -0,0 +1,155 @@
---
on:
workflow_dispatch:
push:
paths-ignore:
- 'android/**'
- 'build/**'
- 'doc/**'
- 'python/**'
- 'subprojects/**'
- 'systemd/**'
- 'win32/**'
branches:
- master
- v0.23.x
pull_request:
paths-ignore:
- 'android/**'
- 'build/**'
- 'doc/**'
- 'python/**'
- 'subprojects/**'
- 'systemd/**'
- 'win32/**'
branches:
- master
- v0.23.x
jobs:
build-linux:
runs-on: ubuntu-latest
env:
CC: 'ccache gcc-10'
CXX: 'ccache g++-10'
steps:
- id: checkout
uses: actions/checkout@v2
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: linux
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
g++-10 libfmt-dev libboost-dev \
libgtest-dev \
libpcre2-dev \
libsystemd-dev libdbus-1-dev \
libicu-dev \
libcurl4-gnutls-dev \
libpcre2-dev \
libavahi-client-dev \
libmad0-dev libmpg123-dev libid3tag0-dev \
libflac-dev libvorbis-dev libopus-dev libogg-dev \
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
libfluidsynth-dev libgme-dev libmikmod-dev libmodplug-dev \
libmpcdec-dev libwavpack-dev libwildmidi-dev \
libsidplay2-dev libsidutils-dev libresid-builder-dev \
libavcodec-dev libavformat-dev \
libmp3lame-dev libtwolame-dev libshine-dev \
libsamplerate0-dev libsoxr-dev \
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
libzzip-dev \
libyajl-dev libexpat-dev \
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
libpulse-dev libshout3-dev \
libsndio-dev \
libmpdclient-dev \
libnfs-dev \
libupnp-dev \
libsqlite3-dev \
libchromaprint-dev \
libgcrypt20-dev
- name: Full Build
uses: BSFishy/meson-build@v1.0.3
with:
action: build
directory: output/full
setup-options: -Ddocumentation=disabled -Dtest=true -Dsystemd=enabled -Dpcre=enabled
options: --verbose
meson-version: 0.56.0
- name: Unit Tests
uses: BSFishy/meson-build@v1.0.3
with:
action: test
directory: output/full
setup-options: -Ddocumentation=disabled -Dtest=true -Dsystemd=enabled -Dpcre=enabled
options: --verbose
meson-version: 0.56.0
- name: Mini Build
uses: BSFishy/meson-build@v1.0.3
with:
action: build
directory: output/mini
setup-options: -Dbuildtype=minsize -Dauto_features=disabled -Dtest=true -Ddaemon=false -Dinotify=false -Depoll=false -Deventfd=false -Dsignalfd=false -Dtcp=false -Ddsd=false -Ddatabase=false -Dneighbor=false -Dcue=false -Dfifo=false -Dhttpd=false -Dpipe=false -Drecorder=false -Dsnapcast=false
options: --verbose
meson-version: 0.56.0
build-macos:
runs-on: macos-latest
steps:
- id: checkout
uses: actions/checkout@v2
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: macos
- uses: actions/setup-python@v1
- name: Install dependencies
run: |
brew install \
meson ninja \
fmt \
boost \
googletest \
icu4c \
ffmpeg \
libnfs \
yajl \
libupnp \
libid3tag \
chromaprint \
libsamplerate \
libsoxr \
flac \
opus \
libvorbis \
faad2 \
wavpack \
libmpdclient
- name: Build
uses: BSFishy/meson-build@v1.0.3
with:
action: build
directory: output
setup-options: -Ddocumentation=disabled -Dtest=true
options: --verbose
meson-version: 0.56.0
- name: Unit Tests
uses: BSFishy/meson-build@v1.0.3
with:
action: test
directory: output
setup-options: -Ddocumentation=disabled -Dtest=true
options: --verbose
meson-version: 0.56.0

@ -11,6 +11,7 @@ jobs:
- meson
- libgtest-dev
- libboost-dev
- libfmt-dev
# Ubuntu Focal (20.04) with GCC 9.3 on big-endian
- os: linux
@ -22,6 +23,7 @@ jobs:
- meson
- libgtest-dev
- libboost-dev
- libfmt-dev
# Ubuntu Focal (20.04) with GCC 9.3 on ARM64
- os: linux
@ -33,6 +35,7 @@ jobs:
- meson
- libgtest-dev
- libboost-dev
- libfmt-dev
# Ubuntu Trusty (16.04) with GCC 8
- os: linux
@ -67,6 +70,7 @@ jobs:
packages:
- ccache
- meson
- fmt
- googletest
- icu4c
- ffmpeg

252
NEWS

@ -1,3 +1,255 @@
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)
* input
- cdio_paranoia: add options "mode" and "skip"
* decoder
- ffmpeg: support FFmpeg 5.1
* filter
- replay gain: fix delayed volume display with handler=mixer
* output
- pipewire: set app icon
* fix bogus volume levels with multiple partitions
* improve iconv detection
* macOS: fix macOS 10 build problem (0.23.8 regression)
* Android
- load mpd.conf from app data directory
ver 0.23.8 (2022/07/09)
* storage
- curl: fix crash if web server does not understand WebDAV
* input
- cdio_paranoia: fix crash if no drive was found
- cdio_paranoia: faster cancellation
- cdio_paranoia: don't scan for replay gain tags
- pipewire: fix playback of very short tracks
- pipewire: drop all buffers before manual song change
- pipewire: fix stuttering after manual song change
- snapcast: fix busy loop while paused
- snapcast: fix stuttering after resuming playback
* mixer
- better error messages
- alsa: fix setting volume before playback starts
- pipewire: fix crash bug
- pipewire: fix volume change events with PipeWire 0.3.53
- pipewire: don't force initial volume=100%
* support libfmt 9
ver 0.23.7 (2022/05/09)
* database
- upnp: support pupnp 1.14
* decoder
- ffmpeg: fix HLS seeking
- opus: fix missing song length on high-latency files
* output
- shout: require at least libshout 2.4.0
* mixer
- pipewire: fix volume restore
- software: update volume of disabled outputs
* support libiconv
ver 0.23.6 (2022/03/14)
* protocol
- support filename "cover.webp" for "albumart" command
- support "readcomments" and "readpicture" on CUE tracks
* decoder
- ffmpeg: fix end-of-file check (update stuck at empty files)
- opus: fix "readpicture" on Opus files
* output
- pipewire: fix crash bug if setting volume before playback starts
- wasapi: fix resume after pause
ver 0.23.5 (2021/12/01)
* protocol
- support relative offsets for "searchadd"
- fix "searchaddpl" bug (bogus error "Bad position")
* database
- upnp: fix crash bug
* tags
- fix MixRamp support
* migrate to PCRE2
* GCC 12 build fixes
ver 0.23.4 (2021/11/11)
* protocol
- add optional position parameter to "searchaddpl"
* decoder
- ffmpeg: support libavcodec 59
* output
- alsa: add option "thesycon_dsd_workaround" to work around device bug
* fix crash on debug builds if startup fails
* systemd
- remove "RuntimeDirectory" directive because it caused problems
- ignore the "pid_file" setting if started as systemd service
* Windows
- enable the "openmpt" decoder plugin
ver 0.23.3 (2021/10/31)
* protocol
- add optional position parameter to "add" and "playlistadd"
- allow range in "playlistdelete"
* database
- fix scanning files with question mark in the name
- inotify: fix use-after-free bug
* output
- alsa: add option "stop_dsd_silence" to work around DSD DAC noise
* macOS: fix libfmt related build failure
* systemd: add "RuntimeDirectory" directive
ver 0.23.2 (2021/10/22)
* protocol
- fix "albumart" timeout bug
* input
- nfs: fix playback bug
* output
- pipewire: send artist and title to PipeWire
- pipewire: DSD support
* neighbor
- mention failed plugin name in error message
* player
- fix cross-fade regression
* fix crash with libfmt versions older than 7
ver 0.23.1 (2021/10/19)
* protocol
- use decimal notation instead of scientific notation
- "load" supports relative positions
* output
- emit "mixer" idle event when replay gain changes volume
- pipewire: emit "mixer" idle events on external volume change
- pipewire: attempt to change the graph sample rate
- snapcast: fix time stamp bug which caused "Failed to get chunk"
* fix libfmt linker problems
* fix broken password authentication
ver 0.23 (2021/10/14)
* protocol
- new command "getvol"
- show the audio format in "playlistinfo"
- support "listfiles" with arbitrary storage plugins
- support relative positions in "addid"
- fix relative positions in "move" and "moveid"
- add "position" parameter to "findadd" and "searchadd"
- add position parameter to "load"
* database
- proxy: require MPD 0.20 or later
- proxy: require libmpdclient 2.11 or later
- proxy: split search into chunks to avoid exceeding the output buffer
- simple: add option to hide CUE target songs
- upnp: support libnpupnp instead of libupnp
* archive
- zzip, iso9660: ignore file names which are invalid UTF-8
* decoder
- openmpt: new plugin
- wavpack: fix WVC file support
* player
- do not cross-fade songs shorter than 20 seconds
* output
- oss: support DSD over PCM
- pipewire: new plugin
- snapcast: new plugin
* tags
- new tags "ComposerSort", "Ensemble", "Movement", "MovementNumber", and "Location"
* split permission "player" from "control"
* add option "host_permissions"
* new build-time dependency: libfmt
ver 0.22.11 (2021/08/24)
* protocol
- fix "albumart" crash
* filter
- ffmpeg: pass "channel_layout" instead of "channels" to buffersrc
- ffmpeg: fix "av_buffersink_get_frame() failed: Resource temporarily unavailable"
- ffmpeg: support double-precision samples (by converting to single precision)
* Android
- build with NDK r23
- playlist_directory defaults to "/sdcard/Android/data/org.musicpd/files/playlists"
ver 0.22.10 (2021/08/06)
* protocol
- support "albumart" for virtual tracks in CUE sheets
* database
- simple: fix crash bug
- simple: fix absolute paths in CUE "as_directory" entries
- simple: prune CUE entries from database for non-existent songs
* input
- curl: fix crash bug after stream with Icy metadata was closed by peer
- tidal: remove defunct unmaintained plugin
* tags
- fix crash caused by bug in TagBuilder and a few potential reference leaks
* output
- httpd: fix missing tag after seeking into a new song
- oss: fix channel order of multi-channel files
* mixer
- alsa: fix yet more rounding errors
ver 0.22.9 (2021/06/23)
* database
- simple: load all .mpdignore files of all parent directories
* tags
- fix "readcomments" and "readpicture" on remote files with ID3 tags
* decoder
- ffmpeg: support the tags "sort_album", "album-sort", "artist-sort"
- ffmpeg: fix build failure with FFmpeg 3.4
* Android
- fix auto-start on boot in Android 8 or later
* Windows
- fix build failure with SQLite
ver 0.22.8 (2021/05/22)
* fix crash bug in "albumart" command (0.22.7 regression)
ver 0.22.7 (2021/05/19)
* protocol
- don't use glibc extension to parse time stamps

@ -14,7 +14,7 @@ For basic installation instructions
- [Manual](http://www.musicpd.org/doc/user/)
- [Forum](http://forum.musicpd.org/)
- [IRC](irc://chat.freenode.net/#mpd)
- [IRC](ircs://irc.libera.chat:6697/#mpd)
- [Bug tracker](https://github.com/MusicPlayerDaemon/MPD/issues/)
# Developers

@ -2,10 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="55"
android:versionName="0.22.7">
android:versionCode="71"
android:versionName="0.23.12">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30"/>
<uses-feature android:name="android.software.leanback"
android:required="false" />
@ -19,6 +19,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application android:allowBackup="true"
android:debuggable="true"
android:requestLegacyExternalStorage="true"
android:icon="@drawable/icon"
android:banner="@drawable/icon"

@ -12,18 +12,30 @@ unsigned_apk = custom_target(
],
)
aligned_apk = custom_target(
'mpd-aligned.apk',
output: 'mpd-aligned.apk',
input: unsigned_apk,
command: [
android_zipalign,
'-f', '4',
'@INPUT@', '@OUTPUT@',
],
)
if get_option('android_debug_keystore') != ''
debug_apk = custom_target(
'mpd-debug.apk',
output: 'mpd-debug.apk',
input: unsigned_apk,
input: aligned_apk,
command: [
jarsigner,
'-keystore', get_option('android_debug_keystore'),
'-storepass', 'android',
'-signedjar', '@OUTPUT@',
'@INPUT@',
'androiddebugkey',
apksigner, 'sign',
'--in', '@INPUT@',
'--out', '@OUTPUT@',
'--debuggable-apk-permitted',
'-ks', get_option('android_debug_keystore'),
'--ks-key-alias', 'androiddebugkey',
'--ks-pass', 'pass:android',
],
build_by_default: true
)
@ -31,29 +43,16 @@ endif
if get_option('android_keystore') != '' and get_option('android_keyalias') != '' and get_option('android_keypass') != ''
unaligned_apk = custom_target(
'mpd-unaligned.apk',
output: 'mpd-unaligned.apk',
input: unsigned_apk,
command: [
jarsigner,
'-digestalg', 'SHA1', '-sigalg', 'MD5withRSA',
'-keystore', get_option('android_keystore'),
'-storepass', get_option('android_keypass'),
'-signedjar', '@OUTPUT@',
'@INPUT@',
get_option('android_keyalias'),
],
)
apk = custom_target(
'mpd.apk',
output: 'mpd.apk',
input: unaligned_apk,
input: aligned_apk,
command: [
android_zipalign,
'-f', '4',
'@INPUT@', '@OUTPUT@',
apksigner, 'sign',
'--in', '@INPUT@',
'--out', '@OUTPUT@',
'-ks', get_option('android_keystore'),
'--ks-key-alias', get_option('android_keyalias'),
'--ks-pass', 'pass:' + get_option('android_keypass'),
],
build_by_default: true
)
endif

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env -S python3 -u
import os, os.path
import sys, subprocess
@ -13,7 +13,7 @@ android_abi = sys.argv[3]
configure_args = sys.argv[4:]
if not os.path.isfile(os.path.join(sdk_path, 'tools', 'android')):
print("SDK not found in", ndk_path, file=sys.stderr)
print("SDK not found in", sdk_path, file=sys.stderr)
sys.exit(1)
if not os.path.isdir(ndk_path):
@ -24,15 +24,13 @@ android_abis = {
'armeabi-v7a': {
'arch': 'arm-linux-androideabi',
'ndk_arch': 'arm',
'toolchain_arch': 'arm-linux-androideabi',
'llvm_triple': 'armv7-linux-androideabi',
'cflags': '-fpic -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp',
'cflags': '-fpic -mfpu=neon -mfloat-abi=softfp',
},
'arm64-v8a': {
'arch': 'aarch64-linux-android',
'ndk_arch': 'arm64',
'toolchain_arch': 'aarch64-linux-android',
'llvm_triple': 'aarch64-linux-android',
'cflags': '-fpic',
},
@ -40,7 +38,6 @@ android_abis = {
'x86': {
'arch': 'i686-linux-android',
'ndk_arch': 'x86',
'toolchain_arch': 'x86',
'llvm_triple': 'i686-linux-android',
'cflags': '-fPIC -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
},
@ -48,7 +45,6 @@ android_abis = {
'x86_64': {
'arch': 'x86_64-linux-android',
'ndk_arch': 'x86_64',
'toolchain_arch': 'x86_64',
'llvm_triple': 'x86_64-linux-android',
'cflags': '-fPIC -m64',
},
@ -84,36 +80,30 @@ class AndroidNdkToolchain:
ndk_arch = abi_info['ndk_arch']
android_api_level = '21'
# select the NDK compiler
gcc_version = '4.9'
install_prefix = os.path.join(arch_path, 'root')
self.arch = arch
self.actual_arch = arch
self.install_prefix = install_prefix
toolchain_path = os.path.join(ndk_path, 'toolchains', abi_info['toolchain_arch'] + '-' + gcc_version, 'prebuilt', build_arch)
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']
toolchain_bin = os.path.join(toolchain_path, 'bin')
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 + ' -gcc-toolchain ' + toolchain_path
common_flags += ' -target ' + llvm_triple
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
# required flags from https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md#additional-required-arguments
common_flags += ' -fno-addrsig'
self.ar = os.path.join(toolchain_bin, arch + '-ar')
self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
self.nm = os.path.join(toolchain_bin, arch + '-nm')
self.strip = os.path.join(toolchain_bin, arch + '-strip')
self.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
@ -151,10 +141,7 @@ class AndroidNdkToolchain:
# default one on the build host
import shutil
bin_dir = os.path.join(install_prefix, 'bin')
try:
os.makedirs(bin_dir)
except:
pass
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
@ -164,7 +151,6 @@ from build.libs import *
thirdparty_libs = [
libmpdclient,
libogg,
libvorbis,
opus,
flac,
libid3tag,
@ -174,7 +160,6 @@ thirdparty_libs = [
ffmpeg,
openssl,
curl,
libexpat,
libnfs,
boost,
]

54
android/gdb.sh Executable file

@ -0,0 +1,54 @@
#!/bin/sh
# This script need the following modification in ANDROID_NDK in order to attach
# to the good :main pid
#--- a/prebuilt/linux-x86_64/bin/ndk-gdb.py
#+++ b/prebuilt/linux-x86_64/bin/ndk-gdb.py
#@@ -669,7 +669,7 @@
# log("Sleeping for {} seconds.".format(args.delay))
# time.sleep(args.delay)
#
#- pids = gdbrunner.get_pids(device, pkg_name)
#+ pids = gdbrunner.get_pids(device, pkg_name + ":main")
# if len(pids) == 0:
# error("Failed to find running process '{}'".format(pkg_name))
# if len(pids) > 1:
SCRIPT_PATH=$(dirname $0)
BUILD_PATH="`pwd`"
TMP_PATH="$BUILD_PATH/gdb"
NDK_GDB_ARGS="--force"
ANDROID_NDK=$1
if [ ! -f $ANDROID_NDK/source.properties ];then
echo "usage: $0 ANDROID_NDK"
exit 1
fi
if [ ! -f $BUILD_PATH/libmpd.so ];then
echo "This script need to be executed from the android build directory"
exit 1
fi
rm -rf "$TMP_PATH"
mkdir -p "$TMP_PATH"
ANDROID_MANIFEST="$SCRIPT_PATH/AndroidManifest.xml"
ABI=`ls "$BUILD_PATH/android/apk/apk/lib" --sort=time | head -n 1`
if [ ! -f "$ANDROID_MANIFEST" -o "$ABI" = "" ]; then
echo "Invalid manifest/ABI, did you try building first ?"
exit 1
fi
mkdir -p "$TMP_PATH"/jni
touch "$TMP_PATH"/jni/Android.mk
echo "APP_ABI := $ABI" > "$TMP_PATH"/jni/Application.mk
DEST=obj/local/$ABI
mkdir -p "$TMP_PATH/$DEST"
cp "$BUILD_PATH/libmpd.so" "$TMP_PATH/$DEST"
cp "$ANDROID_MANIFEST" "$TMP_PATH"
(cd "$TMP_PATH" && bash $ANDROID_NDK/ndk-gdb $NDK_GDB_ARGS)

@ -17,7 +17,7 @@ android_dx = join_paths(android_build_tools_dir, 'dx')
android_zipalign = join_paths(android_build_tools_dir, 'zipalign')
javac = find_program('javac')
jarsigner = find_program('jarsigner')
apksigner = find_program('apksigner')
rsvg_convert = find_program('rsvg-convert')
convert = find_program('convert')
zip = find_program('zip')

@ -23,6 +23,12 @@
android:layout_height="wrap_content"
android:text="@string/checkbox_wakelock" />
<CheckBox
android:id="@+id/pause_on_headphones_disconnect"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/checkbox_pause_on_headphones_disconnect" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"

@ -8,4 +8,5 @@
<string name="toggle_button_run_off">MPD is not running</string>
<string name="checkbox_run_on_boot">Run MPD automatically on boot</string>
<string name="checkbox_wakelock">Prevent suspend when MPD is running (Wakelock)</string>
<string name="checkbox_pause_on_headphones_disconnect">Pause MPD when headphones disconnect</string>
</resources>

@ -13,7 +13,7 @@ GENCLASS="$D/classes"
GENINCLUDE="$D/include"
mkdir -p "$GENSRC/$JAVA_PKG_PATH"
"$JAVAC" -source 1.6 -target 1.6 -Xlint:-options \
"$JAVAC" -source 1.7 -target 1.7 -Xlint:-options \
-cp "$CLASSPATH" \
-h "$GENINCLUDE" \
-d "$GENCLASS" \

@ -33,4 +33,5 @@ public class Bridge {
public static native void run(Context context, LogListener logListener);
public static native void shutdown();
public static native void pause();
}

@ -5,6 +5,7 @@ interface IMain
{
void start();
void stop();
void setPauseOnHeadphonesDisconnect(boolean enabled);
void setWakelockEnabled(boolean enabled);
boolean isRunning();
void registerCallback(IMainCallback cb);

@ -24,10 +24,13 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.media.AudioManager;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
@ -55,6 +58,7 @@ public class Main extends Service implements Runnable {
private String mError = null;
private final RemoteCallbackList<IMainCallback> mCallbacks = new RemoteCallbackList<IMainCallback>();
private final IBinder mBinder = new MainStub(this);
private boolean mPauseOnHeadphonesDisconnect = false;
private PowerManager.WakeLock mWakelock = null;
static class MainStub extends IMain.Stub {
@ -68,6 +72,9 @@ public class Main extends Service implements Runnable {
public void stop() {
mService.stop();
}
public void setPauseOnHeadphonesDisconnect(boolean enabled) {
mService.setPauseOnHeadphonesDisconnect(enabled);
}
public void setWakelockEnabled(boolean enabled) {
mService.setWakelockEnabled(enabled);
}
@ -191,6 +198,18 @@ public class Main extends Service implements Runnable {
if (mThread != null)
return;
IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!mPauseOnHeadphonesDisconnect)
return;
if (intent.getAction() == AudioManager.ACTION_AUDIO_BECOMING_NOISY)
pause();
}
}, filter);
final Intent mainIntent = new Intent(this, Settings.class);
mainIntent.setAction("android.intent.action.MAIN");
mainIntent.addCategory("android.intent.category.LAUNCHER");
@ -241,6 +260,21 @@ public class Main extends Service implements Runnable {
stopSelf();
}
private void pause() {
if (mThread != null) {
if (mThread.isAlive()) {
synchronized (this) {
if (mStatus == MAIN_STATUS_STARTED)
Bridge.pause();
}
}
}
}
private void setPauseOnHeadphonesDisconnect(boolean enabled) {
mPauseOnHeadphonesDisconnect = enabled;
}
private void setWakelockEnabled(boolean enabled) {
if (enabled && mWakelock == null) {
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
@ -368,6 +402,19 @@ public class Main extends Service implements Runnable {
}
}
public boolean setPauseOnHeadphonesDisconnect(boolean enabled) {
synchronized (this) {
if (mIMain != null) {
try {
mIMain.setPauseOnHeadphonesDisconnect(enabled);
return true;
} catch (RemoteException e) {
}
}
return false;
}
}
public boolean setWakelockEnabled(boolean enabled) {
synchronized (this) {
if (mIMain != null) {
@ -414,6 +461,15 @@ public class Main extends Service implements Runnable {
* start Main service without any callback
*/
public static void start(Context context, boolean wakelock) {
context.startService(new Intent(context, Main.class).putExtra("wakelock", wakelock));
Intent intent = new Intent(context, Main.class)
.putExtra("wakelock", wakelock);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
/* in Android 8+, we need to use this method
or else we'll get "IllegalStateException:
app is in background" */
context.startForegroundService(intent);
else
context.startService(intent);
}
}

@ -25,16 +25,18 @@ import android.content.Intent;
import android.util.Log;
public class Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("Receiver", "onReceive: " + intent);
if (intent.getAction() == "android.intent.action.BOOT_COMPLETED") {
if (Settings.Preferences.getBoolean(context,
Settings.Preferences.KEY_RUN_ON_BOOT, false)) {
final boolean wakelock = Settings.Preferences.getBoolean(context,
Settings.Preferences.KEY_WAKELOCK, false);
Main.start(context, wakelock);
}
}
}
@Override
public void onReceive(Context context, Intent intent) {
Log.d("Receiver", "onReceive: " + intent);
if (intent.getAction() == "android.intent.action.BOOT_COMPLETED") {
if (Settings.Preferences.getBoolean(context,
Settings.Preferences.KEY_RUN_ON_BOOT,
false)) {
final boolean wakelock =
Settings.Preferences.getBoolean(context,
Settings.Preferences.KEY_WAKELOCK, false);
Main.start(context, wakelock);
}
}
}
}

@ -59,6 +59,7 @@ public class Settings extends Activity {
public static class Preferences {
public static final String KEY_RUN_ON_BOOT ="run_on_boot";
public static final String KEY_WAKELOCK ="wakelock";
public static final String KEY_PAUSE_ON_HEADPHONES_DISCONNECT ="pause_on_headphones_disconnect";
public static SharedPreferences get(Context context) {
return context.getSharedPreferences(TAG, MODE_PRIVATE);
@ -154,6 +155,9 @@ public class Settings extends Activity {
if (Preferences.getBoolean(Settings.this,
Preferences.KEY_WAKELOCK, false))
mClient.setWakelockEnabled(true);
if (Preferences.getBoolean(Settings.this,
Preferences.KEY_PAUSE_ON_HEADPHONES_DISCONNECT, false))
mClient.setPauseOnHeadphonesDisconnect(true);
} else {
mClient.stop();
}
@ -179,6 +183,15 @@ public class Settings extends Activity {
}
};
private final OnCheckedChangeListener mOnPauseOnHeadphonesDisconnectChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Preferences.putBoolean(Settings.this, Preferences.KEY_PAUSE_ON_HEADPHONES_DISCONNECT, isChecked);
if (mClient != null && mClient.isRunning())
mClient.setPauseOnHeadphonesDisconnect(isChecked);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
/* TODO: this sure is the wrong place to request
@ -211,6 +224,11 @@ public class Settings extends Activity {
if (Preferences.getBoolean(this, Preferences.KEY_WAKELOCK, false))
checkbox.setChecked(true);
checkbox = (CheckBox) findViewById(R.id.pause_on_headphones_disconnect);
checkbox.setOnCheckedChangeListener(mOnPauseOnHeadphonesDisconnectChangeListener);
if (Preferences.getBoolean(this, Preferences.KEY_PAUSE_ON_HEADPHONES_DISCONNECT, false))
checkbox.setChecked(true);
super.onCreate(savedInstanceState);
}

66
doc/client.rst Normal file

@ -0,0 +1,66 @@
Client Developer's Manual
#########################
Introduction
************
MPD is a music player without a user interface. The user interface
will be provided by independent clients, which connect to MPD over
socket connections (TCP or local sockets).
This chapter describes how to develop a client.
Before you develop a new client, consider joining an existing client
project. There are many clients, but few are mature; we need fewer,
but better clients.
Client Libraries
****************
There are many libraries which help with connecting to MPD. If you
develop a MPD client, use a library instead of reinventing the wheel.
The MPD website has a list of libraries: https://www.musicpd.org/libs/
Connecting to MPD
*****************
Do not hard-code your client to connect to ``localhost:6600``.
Instead, use the defaults of the client library. For example, with
:program:`libmpdclient`, don't do::
c = mpd_connection_new("localhost", 6600, 30000);
Instead, do::
c = mpd_connection_new(NULL, 0, 0);
This way, the library can choose the best defaults, maybe derived from
environment variables, so all MPD clients use the same settings.
If you need to reimplement those defaults (or if you are developing a
client library), this is a good set of addresses to attempt to connect
to:
- if the environment variable :envvar:`MPD_HOST` is set:
``$MPD_HOST:$MPD_PORT`` (:envvar:`MPD_PORT` defaulting to 6600)
- if the environment variable :envvar:`XDG_RUNTIME_DIR` is set:
``$XDG_RUNTIME_DIR/mpd/socket``
- :file:`/run/mpd/socket`
- ``localhost:$MPD_PORT`` (:envvar:`MPD_PORT` defaulting to 6600)
Environment Variables
*********************
The following environment variables should be obeyed by all clients
(preferably by the client library):
- :envvar:`MPD_HOST`: the host (or local socket path) to connect to;
on Linux, this may start with a ``@`` to connect to an abstract
socket. To use a password with MPD, set :envvar:`MPD_HOST` to
``password@host`` (then abstract socket requires double ``@``:
``password@@socket``).
- :envvar:`MPD_PORT`: the port number; defaults to 6600.
- :envvar:`MPD_TIMEOUT`: timeout for connecting to MPD and for waiting
for MPD's response in seconds. A good default is 30 seconds.

@ -30,7 +30,7 @@ master_doc = 'index'
# General information about the project.
project = 'Music Player Daemon'
copyright = '2003-2020 The Music Player Daemon Project'
copyright = '2003-2021 The Music Player Daemon Project'
author = 'Max Kellermann'
# The version info for the project you're documenting, acts as replacement for
@ -38,16 +38,19 @@ author = 'Max Kellermann'
# built documents.
#
# The short X.Y version.
version = '0.22.7'
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.
release = version
#release = version + '~git'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# 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
# non-false value, then it is used:
@ -107,6 +110,7 @@ html_theme = 'classic'
# documentation.
#
# html_theme_options = {}
html_theme_options = {"sidebarwidth": "300px"}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []

@ -8,8 +8,15 @@ Music Player Daemon
user
plugins
developer
client
protocol
.. toctree::
:maxdepth: 1
:caption: man pages:
mpd.1
mpd.conf.5
Indices and tables
==================

@ -14,6 +14,7 @@ if get_option('html_manual')
input: [
'index.rst', 'user.rst', 'developer.rst',
'plugins.rst',
'client.rst',
'protocol.rst',
'conf.py',
],

@ -128,23 +128,6 @@ audio_output
no audio_output section is specified, then MPD will scan for a usable audio
output.
replaygain <off or album or track or auto>
If specified, mpd will adjust the volume of songs played using ReplayGain
tags (see https://wiki.hydrogenaud.io/index.php?title=Replaygain).
Setting this to "album" will
adjust volume using the album's ReplayGain tags, while setting it to "track"
will adjust it using the track ReplayGain tags. "auto" uses the track
ReplayGain tags if random play is activated otherwise the album ReplayGain
tags. Currently only FLAC, Ogg Vorbis, Musepack, and MP3 (through ID3v2
ReplayGain tags, not APEv2) are supported.
replaygain_preamp <-15 to 15>
This is the gain (in dB) applied to songs with ReplayGain tags.
volume_normalization <yes or no>
If yes, mpd will normalize the volume of songs as they play. The default is
no.
filesystem_charset <charset>
This specifies the character set used for the filesystem. A list of supported
character sets can be obtained by running "iconv -l". The default is

@ -26,22 +26,25 @@
# files over an accepted protocol.
#
#db_file "~/.mpd/database"
#
# These settings are the locations for the daemon log files for the daemon.
# These logs are great for troubleshooting, depending on your log_level
# settings.
#
# The special value "syslog" makes MPD use the local syslog daemon. This
# setting defaults to logging to syslog.
#
#log_file "~/.mpd/log"
# If you use systemd, do not configure a log_file. With systemd, MPD
# defaults to the systemd journal, which is fine.
#
#log_file "~/.mpd/log"
# This setting sets the location of the file which stores the process ID
# for use of mpd --kill and some init scripts. This setting is disabled by
# default and the pid file will not be stored.
#
#pid_file "~/.mpd/pid"
# If you use systemd, do not configure a pid_file.
#
#pid_file "~/.mpd/pid"
# This setting sets the location of the file which contains information about
# most variables to get MPD back into the same general shape it was in before
# it was brought down. This setting is disabled by default and the server
@ -76,7 +79,7 @@
# This setting sets the address for the daemon to listen on. Careful attention
# should be paid if this is assigned to anything other than the default, any.
# This setting can deny access to control of the daemon. Not effective if
# systemd socket activiation is in use.
# systemd socket activation is in use.
#
# For network
#bind_to_address "any"
@ -178,11 +181,11 @@
#
#database {
# plugin "simple"
# path "~/.local/share/mpd/db
# path "~/.local/share/mpd/db"
# cache_directory "~/.local/share/mpd/cache"
#}
#
# An example of database config for a sattelite setup
# An example of database config for a satellite setup
#
#music_directory "nfs://fileserver.local/srv/mp3"
#database {

@ -23,11 +23,23 @@ The default plugin. Stores a copy of the database in memory. A file is used for
- The path of the cache directory for additional storages mounted at runtime. This setting is necessary for the **mount** protocol command.
* - **compress yes|no**
- Compress the database file using gzip? Enabled by default (if built with zlib).
* - **hide_playlist_targets yes|no**
- Hide songs which are referenced by playlists? Thas is,
playlist files which are represented in the database as virtual
directories (playlist plugin setting ``as_directory``). This
option is enabled by default and avoids duplicate songs; one
copy for the original file, and another copy in the virtual
directory of a CUE file referring to it.
proxy
-----
Provides access to the database of another :program:`MPD` instance using libmpdclient. This is useful when you mount the music directory via NFS/SMB, and the file server already runs a :program:`MPD` instance. Only the file server needs to update the database.
Provides access to the database of another :program:`MPD` instance
using `libmpdclient
<https://www.musicpd.org/libs/libmpdclient/>`_. This is useful when
you mount the music directory via NFS/SMB, and the file server already
runs a :program:`MPD` (0.20 or newer) instance. Only the file server
needs to update the database.
.. list-table::
:widths: 20 80
@ -49,6 +61,15 @@ upnp
Provides access to UPnP media servers.
.. list-table::
:widths: 20 80
:header-rows: 1
* - Setting
- Description
* - **interface**
- Interface used to discover media servers. Decided by upnp if left unconfigured.
Storage plugins
===============
@ -185,6 +206,11 @@ Plays audio CDs using libcdio. The URI has the form: "cdda://[DEVICE][/TRACK]".
- If the CD drive does not specify a byte order, MPD assumes it is the CPU's native byte order. This setting allows overriding this.
* - **speed N**
- Request CDParanoia cap the extraction speed to Nx normal CD audio rotation speed, keeping the drive quiet.
* - **mode disable|overlap|full**
- Set the paranoia mode; ``disable`` means no fixups, ``overlap``
performs overlapped reads, and ``full`` enables all options.
* - **skip yes|no**
- If set to ``no``, then never skip failed reads.
curl
----
@ -193,8 +219,9 @@ Opens remote files or streams over HTTP using libcurl.
Note that unless overridden by the below settings (e.g. by setting
them to a blank value), general curl configuration from environment
variables such as ``http_proxy`` or specified in :file:`~/.curlrc`
will be in effect.
variables such as ``http_proxy`` will be in effect.
User name and password are read from an optional :file:`~/.netrc`, :file:`~/.curlrc` is not read.
.. list-table::
:widths: 20 80
@ -210,6 +237,8 @@ will be in effect.
- Verify the peer's SSL certificate? `More information <http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html>`_.
* - **verify_host yes|no**
- Verify the certificate's name against host? `More information <http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html>`_.
* - **cacert**
- Set path to Certificate Authority (CA) bundle `More information <https://curl.se/libcurl/c/CURLOPT_CAINFO.html>`_.
ffmpeg
------
@ -295,37 +324,6 @@ in the form ``qobuz://track/ID``, e.g.:
* - **format_id N**
- The `Qobuz format identifier <https://github.com/Qobuz/api-documentation/blob/master/endpoints/track/getFileUrl.md#parameters>`_, i.e. a number which chooses the format and quality to be requested from Qobuz. The default is "5" (320 kbit/s MP3).
tidal
-----
Play songs from the commercial streaming service `Tidal
<http://tidal.com/>`_. It plays URLs in the form ``tidal://track/ID``,
e.g.:
.. warning::
This plugin is currently defunct because Tidal has changed the
protocol and decided not to share documentation.
.. code-block:: none
mpc add tidal://track/59727857
.. list-table::
:widths: 20 80
:header-rows: 1
* - Setting
- Description
* - **token TOKEN**
- The Tidal application token. Since Tidal is unwilling to assign a token to MPD, this needs to be reverse-engineered from another (approved) Tidal client.
* - **username USERNAME**
- The Tidal user name.
* - **password PASSWORD**
- The Tidal password.
* - **audioquality Q**
- The Tidal "audioquality" parameter. Possible values: HI_RES, LOSSLESS, HIGH, LOW. Default is HIGH.
.. _decoder_plugins:
Decoder plugins
@ -482,9 +480,39 @@ Module player based on MODPlug.
* - Setting
- Description
* - **resampling_mode nearest|linear|spline|fir**
- Sets the resampling mode. "nearest" disables interpolation (good for chiptunes). "linear" makes modplug use linear interpolation (fast, good quality). "spline" makes modplug use cubic spline interpolation (high quality). "fir" makes modplug use 8-tap fir filter (extremely high quality). Defaults to "fir".
* - **loop_count**
- Number of times to loop the module if it uses backward loops. Default is 0 which prevents looping. -1 loops forever.
openmpt
-------
Module player based on `libopenmpt <https://lib.openmpt.org>`_.
.. list-table::
:widths: 20 80
:header-rows: 1
* - Setting
- Description
* - **repeat_count**
- Set how many times the module repeats. -1: repeat forever. 0: play once, repeat zero times (the default). n>0: play once and repeat n times after that.
* - **stereo_separation**
- Sets the stereo separation. The supported value range is [0,200]. Defaults to 100.
* - **interpolation_filter 0|1|2|4|8**
- Sets the interpolation filter. 0: internal default. 1: no interpolation (zero order hold). 2: linear interpolation. 4: cubic interpolation. 8: windowed sinc with 8 taps. Defaults to 0.
* - **override_mptm_interp_filter yes|no**
- If `interpolation_filter` has been changed, setting this to yes will force all MPTM modules to use that interpolation filter. If set to no, MPTM modules will play with their own interpolation filter regardless of the value of `interpolation_filter`. Defaults to no.
* - **volume_ramping**
- Sets the amount of volume ramping done by the libopenmpt mixer. The default value is -1, which indicates a recommended default value. The meaningful value range is [-1..10]. A value of 0 completely disables volume ramping. This might cause clicks in sound output. Higher values imply slower/softer volume ramps.
* - **sync_samples yes|no**
- Syncs sample playback when seeking. Defaults to yes.
* - **emulate_amiga yes|no**
- Enables the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. Defaults to yes.
* - **emulate_amiga_type**
- Configures the filter type to use for the Amiga resampler. Supported values are: "auto": Filter type is chosen by the library and might change. This is the default. "a500": Amiga A500 filter. "a1200": Amiga A1200 filter. "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future. Defaults to "auto". Requires libopenmpt 0.5 or higher.
mpcdec
------
@ -579,6 +607,10 @@ Encodes into `FLAC <https://xiph.org/flac/>`_ (lossless).
- Description
* - **compression**
- Sets the libFLAC compression level. The levels range from 0 (fastest, least compression) to 8 (slowest, most compression).
* - **oggflac yes|no**
- Configures if the stream should be Ogg FLAC versus native FLAC. Defaults to "no" (use native FLAC).
* - **oggchaining yes|no**
- Configures if the stream should use Ogg Chaining for in-stream metadata. Defaults to "no". Setting this to "yes" also enables Ogg FLAC.
lame
----
@ -643,11 +675,15 @@ Encodes into `Ogg Opus <http://www.opus-codec.org/>`_.
* - Setting
- Description
* - **bitrate**
- Sets the data rate in bit per second. The special value "auto" lets libopus choose a rate (which is the default), and "max" uses the maximum possible data rate.
- Sets the data rate in bits per second. The special value "auto" lets libopus choose a rate (which is the default), and "max" uses the maximum possible data rate.
* - **complexity**
- Sets the `Opus complexity <https://wiki.xiph.org/OpusFAQ#What_is_the_complexity_of_Opus.3F>`_.
* - **signal**
- Sets the Opus signal type. Valid values are "auto" (the default), "voice" and "music".
* - **vbr yes|no|constrained**
- Sets the vbr mode. Setting to "yes" (default) enables variable bitrate, "no" forces constant bitrate and frame sizes, "constrained" uses constant bitrate analogous to CBR in AAC and MP3.
* - **packet_loss**
- Sets the expected packet loss percentage. This value can be increased from the default "0" for a more redundant stream at the expense of quality.
* - **opustags yes|no**
- Configures how metadata is interleaved into the stream. If set to yes, then metadata is inserted using ogg stream chaining, as specified in :rfc:`7845`. If set to no (the default), then ogg stream chaining is avoided and other output-dependent method is used, if available.
@ -715,7 +751,7 @@ A resampler using `libsamplerate <http://www.mega-nerd.com/SRC/>`_ a.k.a. Secret
* - Name
- Description
* - **type**
- The interpolator type. See below for a list of known types.
- The interpolator type. Defaults to :samp:`2`. See below for a list of known types.
The following converter types are provided by libsamplerate:
@ -815,6 +851,16 @@ The `Advanced Linux Sound Architecture (ALSA) <http://www.alsa-project.org/>`_ p
- If set to no, then libasound will not attempt to convert between different sample formats (16 bit, 24 bit, floating point, ...).
* - **dop yes|no**
- If set to yes, then DSD over PCM according to the `DoP standard <http://dsd-guide.com/dop-open-standard>`_ is enabled. This wraps DSD samples in fake 24 bit PCM, and is understood by some DSD capable products, but may be harmful to other hardware. Therefore, the default is no and you can enable the option at your own risk.
* - **stop_dsd_silence yes|no**
- If enabled, silence is played before manually stopping playback
("stop" or "pause") in DSD mode (native DSD or DoP). This is a
workaround for some DACs which emit noise when stopping DSD
playback.
* - **thesycon_dsd_workaround yes|no**
- If enabled, enables a workaround for a bug in Thesycon USB
audio receivers. On these devices, playing DSD512 or PCM
causes all subsequent attempts to play other DSD rates to fail,
which can be fixed by briefly playing PCM at 44.1 kHz.
* - **allowed_formats F1 F2 ...**
- Specifies a list of allowed audio formats, separated by a space. All items may contain asterisks as a wild card, and may be followed by "=dop" to enable DoP (DSD over PCM) for this particular format. The first matching format is used, and if none matches, MPD chooses the best fallback of this list.
@ -990,6 +1036,8 @@ On Linux, OSS has been superseded by ALSA. Use the ALSA output plugin :ref:`alsa
- Description
* - **device PATH**
- Sets the path of the PCM device. If not specified, then MPD will attempt to open /dev/sound/dsp and /dev/dsp.
* - **dop yes|no**
- If set to yes, then DSD over PCM according to the `DoP standard <http://dsd-guide.com/dop-open-standard>`_ is enabled. This wraps DSD samples in fake 24 bit PCM, and is understood by some DSD capable products, but may be harmful to other hardware. Therefore, the default is no and you can enable the option at your own risk.
The according hardware mixer plugin understands the following settings:
@ -1052,6 +1100,28 @@ The pipe plugin starts a program and writes raw PCM data into its standard input
* - **command CMD**
- This command is invoked with the shell.
pipewire
--------
Connect to a `PipeWire <https://pipewire.org/>`_ server. Requires
``libpipewire``.
.. list-table::
:widths: 20 80
:header-rows: 1
* - Setting
- Description
* - **target NAME**
- Link to the given target. If not specified, let the PipeWire
manager select a target. To get a list of available targets,
type ``pw-cli dump short Node``
* - **remote NAME**
- The name of the remote to connect to. The default is
``pipewire-0``.
* - **dsd yes|no**
- Enable DSD playback. This requires PipeWire 0.38.
.. _pulse_plugin:
pulse
@ -1107,8 +1177,6 @@ You must set a format.
- Sets the host name of the `ShoutCast <http://www.shoutcast.com/>`_ / `IceCast <http://icecast.org/>`_ server.
* - **port PORTNUMBER**
- Connect to this port number on the specified host.
* - **timeout SECONDS**
- Set the timeout for the shout connection in seconds. Defaults to 2 seconds.
* - **protocol icecast2|icecast1|shoutcast**
- Specifies the protocol that wil be used to connect to the server. The default is "icecast2".
* - **tls disabled|auto|auto_no_plain|rfc2818|rfc2817**
@ -1144,6 +1212,34 @@ audio API. Its primary use is local playback on Android, where
floating point samples.
snapcast
--------
Snapcast is a multiroom client-server audio player. This plugin
allows MPD to act as a `Snapcast
<https://github.com/badaix/snapcast>`__ server. Snapcast clients
connect to it and receive audio data from MPD.
You must set a format.
.. list-table::
:widths: 20 80
:header-rows: 1
* - Setting
- Description
* - **port P**
- Binds the Snapcast server to the specified port. The default
port is :samp:`1704`.
* - **bind_to_address ADDR**
- Binds the Snapcast server to the specified address. Multiple
addresses in parallel are not supported. The default is to
bind on all addresses on port :samp:`1704`.
* - **zeroconf yes|no**
- Publish the Snapcast server as service type ``_snapcast._tcp``
via Zeroconf (Avahi or Bonjour). Default is :samp:`yes`.
solaris
-------
The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio.
@ -1200,7 +1296,7 @@ This plugin requires building with ``libavfilter`` (FFmpeg).
* - **graph "..."**
- Specifies the ``libavfilter`` graph; read the `FFmpeg
documentation
<https://libav.org/documentation/libavfilter.html#Filtergraph-syntax-1>`_
<https://ffmpeg.org/ffmpeg-filters.html#Filtergraph-syntax-1>`_
for details

@ -286,10 +286,15 @@ The following tags are supported by :program:`MPD`:
* **date**: the song's release date. This is usually a 4-digit year.
* **originaldate**: the song's original release date.
* **composer**: the artist who composed the song.
* **composersort**: same as composer, but for sorting.
* **performer**: the artist who performed the song.
* **conductor**: the conductor who conducted the song.
* **work**: `"a work is a distinct intellectual or artistic creation,
which can be expressed in the form of one or more audio recordings" <https://musicbrainz.org/doc/Work>`_
* **ensemble**: the ensemble performing this song, e.g. "Wiener Philharmoniker".
* **movement**: name of the movement, e.g. "Andante con moto".
* **movementnumber**: movement number, e.g. "2" or "II".
* **location**: location of the recording, e.g. "Royal Albert Hall".
* **grouping**: "used if the sound belongs to a larger category of
sounds/music" (`from the IDv2.4.0 TIT1 description
<http://id3.org/id3v2.4.0-frames>`_).
@ -474,7 +479,7 @@ Querying :program:`MPD`'s status
current song in seconds, but with higher resolution.
- ``duration`` [#since_0_20]_: Duration of the current song in seconds.
- ``bitrate``: instantaneous bitrate in kbps
- ``xfade``: ``crossfade`` in seconds
- ``xfade``: ``crossfade`` in seconds (see :ref:`crossfading`)
- ``mixrampdb``: ``mixramp`` threshold in dB
- ``mixrampdelay``: ``mixrampdelay`` in seconds
- ``audio``: The format emitted by the decoder plugin during
@ -514,17 +519,19 @@ Playback options
.. _command_crossfade:
:command:`crossfade {SECONDS}`
Sets crossfading between songs.
Sets crossfading between songs. See :ref:`crossfading`.
.. _command_mixrampdb:
:command:`mixrampdb {deciBels}`
Sets the threshold at which songs will be overlapped. Like crossfading but doesn't fade the track volume, just overlaps. The songs need to have MixRamp tags added by an external tool. 0dB is the normalized maximum volume so use negative values, I prefer -17dB. In the absence of mixramp tags crossfading will be used. See http://sourceforge.net/projects/mixramp
Sets the threshold at which songs will be overlapped.
See :ref:`mixramp`.
.. _command_mixrampdelay:
:command:`mixrampdelay {SECONDS}`
Additional time subtracted from the overlap calculated by mixrampdb. A value of "nan" disables MixRamp overlapping and falls back to crossfading.
See :ref:`mixramp`.
.. _command_random:
@ -538,12 +545,31 @@ Playback options
Sets repeat state to ``STATE``,
``STATE`` should be 0 or 1.
If enabled, MPD keeps repeating the whole queue (:ref:`single mode
<command_single>` disabled) or the current song (:ref:`single mode
<command_single>` enabled).
If :ref:`random mode <command_random>` is also enabled, the
playback order will be shuffled each time the queue gets repeated.
.. _command_setvol:
:command:`setvol {VOL}`
Sets volume to ``VOL``, the range of
volume is 0-100.
.. _command_getvol:
:command:`getvol` [#since_0_23]_
Read the volume. The result is a ``volume:`` line like in
:ref:`status <command_status>`. If there is no mixer, MPD will
emit an empty response. Example::
getvol
volume: 42
OK
.. _command_single:
:command:`single {STATE}` [#since_0_15]_
@ -672,11 +698,14 @@ Whenever possible, ids should be used.
.. _command_add:
:command:`add {URI}`
:command:`add {URI} [POSITION]`
Adds the file ``URI`` to the playlist
(directories add recursively). ``URI``
can also be a single file.
The position parameter is the same as in :ref:`addid
<command_addid>`. [#since_0_23_3]_
Clients that are connected via local socket may add arbitrary
local files (URI is an absolute path). Example::
@ -692,6 +721,13 @@ Whenever possible, ids should be used.
Id: 999
OK
If the second parameter is given, then the song is inserted at the
specified position. If the parameter starts with ``+`` or ``-``,
then it is relative to the current song [#since_0_23]_; e.g. ``+0``
inserts right after the current song and ``-0`` inserts right
before the current song (i.e. zero songs between the current song
and the newly added song).
.. _command_clear:
:command:`clear`
@ -715,14 +751,22 @@ Whenever possible, ids should be used.
at ``START:END`` [#since_0_15]_ to ``TO``
in the playlist.
If ``TO`` starts with ``+`` or ``-``, then it is relative to the
current song; e.g. ``+0`` moves to right after the current song
and ``-0`` moves to right before the current song (i.e. zero songs
between the current song and the moved range).
.. _command_moveid:
:command:`moveid {FROM} {TO}`
Moves the song with ``FROM`` (songid) to
``TO`` (playlist index) in the
playlist. If ``TO`` is negative, it
is relative to the current song in the playlist (if
there is one).
playlist.
If ``TO`` starts with ``+`` or ``-``, then it is relative to the
current song; e.g. ``+0`` moves to right after the current song
and ``-0`` moves to right before the current song (i.e. zero songs
between the current song and the moved song).
.. _command_playlist:
@ -736,8 +780,8 @@ Whenever possible, ids should be used.
.. _command_playlistfind:
:command:`playlistfind {FILTER}`
Finds songs in the queue with strict
matching.
Search the queue for songs matching
``FILTER`` (see :ref:`Filters <filter_syntax>`).
.. _command_playlistid:
@ -757,8 +801,10 @@ Whenever possible, ids should be used.
.. _command_playlistsearch:
:command:`playlistsearch {FILTER}`
Searches case-insensitively for partial matches in the
queue.
Search the queue for songs matching
``FILTER`` (see :ref:`Filters <filter_syntax>`).
Parameters have the same meaning as for :ref:`find
<command_playlistfind>`, except that search is not case sensitive.
.. _command_plchanges:
@ -885,19 +931,28 @@ remote playlists (absolute URI with a supported scheme).
.. _command_load:
:command:`load {NAME} [START:END]`
:command:`load {NAME} [START:END] [POSITION]`
Loads the playlist into the current queue. Playlist
plugins are supported. A range may be specified to load
only a part of the playlist.
The ``POSITION`` parameter specifies where the songs will be
inserted into the queue; it can be relative as described in
:ref:`addid <command_addid>`. (This requires specifying the range
as well; the special value `0:` can be used if the whole playlist
shall be loaded at a certain queue position.) [#since_0_23_1]_
.. _command_playlistadd:
:command:`playlistadd {NAME} {URI}`
:command:`playlistadd {NAME} {URI} [POSITION]`
Adds ``URI`` to the playlist
`NAME.m3u`.
`NAME.m3u` will be created if it does
not exist.
The ``POSITION`` parameter specifies where the songs will be
inserted into the playlist. [#since_0_23_3]_
.. _command_playlistclear:
:command:`playlistclear {NAME}`
@ -909,6 +964,8 @@ remote playlists (absolute URI with a supported scheme).
Deletes ``SONGPOS`` from the
playlist `NAME.m3u`.
The second parameter can be a range. [#since_0_23_3]_
.. _command_playlistmove:
:command:`playlistmove {NAME} {FROM} {TO}`
@ -1022,11 +1079,11 @@ The music database
.. _command_findadd:
:command:`findadd {FILTER} [sort {TYPE}] [window {START:END}]`
:command:`findadd {FILTER} [sort {TYPE}] [window {START:END}] [position POS]`
Search the database for songs matching
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
the queue. Parameters have the same meaning as for
:ref:`find <command_find>`.
:ref:`find <command_find>` and :ref:`searchadd <command_searchadd>`.
.. _command_list:
@ -1167,16 +1224,21 @@ The music database
.. _command_searchadd:
:command:`searchadd {FILTER} [sort {TYPE}] [window {START:END}]`
:command:`searchadd {FILTER} [sort {TYPE}] [window {START:END}] [position POS]`
Search the database for songs matching
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
the queue.
Parameters have the same meaning as for :ref:`search <command_search>`.
The ``position`` parameter specifies where the songs will be
inserted. [#since_0_23]_
It can be relative to the current song as in :ref:`addid
<command_addid>`. [#since_0_23_5]_
.. _command_searchaddpl:
:command:`searchaddpl {NAME} {FILTER} [sort {TYPE}] [window {START:END}]`
:command:`searchaddpl {NAME} {FILTER} [sort {TYPE}] [window {START:END}] [position POS]`
Search the database for songs matching
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
the playlist named ``NAME``.
@ -1185,6 +1247,9 @@ The music database
Parameters have the same meaning as for :ref:`search <command_search>`.
The ``position`` parameter specifies where the songs will be
inserted. [#since_0_23_4]_
.. _command_update:
:command:`update [URI]`
@ -1603,3 +1668,8 @@ client-to-client messages are local to the current partition.
.. [#since_0_20] Since :program:`MPD` 0.20
.. [#since_0_21] Since :program:`MPD` 0.21
.. [#since_0_22_4] Since :program:`MPD` 0.22.4
.. [#since_0_23] Since :program:`MPD` 0.23
.. [#since_0_23_1] Since :program:`MPD` 0.23.1
.. [#since_0_23_3] Since :program:`MPD` 0.23.3
.. [#since_0_23_4] Since :program:`MPD` 0.23.4
.. [#since_0_23_5] Since :program:`MPD` 0.23.5

@ -36,7 +36,9 @@ Installing on Android
An experimental Android build is available on Google Play. After installing and launching it, :program:`MPD` will scan the music in your Music directory and you can control it as usual with a :program:`MPD` client.
If you need to tweak the configuration, you can create a file called :file:`mpd.conf` on the data partition (the directory which is returned by Android's :dfn:`getExternalStorageDirectory()` API function).
If you need to tweak the configuration, you can create a file called
:file:`mpd.conf` in MPD's data directory on the external storage
(usually :file:`Android/data/org.musicpd/files/mpd.conf`).
ALSA is not available on Android; only the :ref:`OpenSL ES
<sles_output>` output plugin can be used for local playback.
@ -55,8 +57,8 @@ and unpack it (or `clone the git repository
In any case, you need:
* a C++17 compiler (e.g. GCC 8 or clang 5)
* `Meson 0.49.0 <http://mesonbuild.com/>`__ and `Ninja
* a C++17 compiler (e.g. GCC 8 or clang 7)
* `Meson 0.56.0 <http://mesonbuild.com/>`__ and `Ninja
<https://ninja-build.org/>`__
* Boost 1.58
* pkg-config
@ -64,12 +66,13 @@ In any case, you need:
Each plugin usually needs a codec library, which you also need to
install. Check the :doc:`plugins` for details about required libraries
For example, the following installs a fairly complete list of build dependencies on Debian Buster:
For example, the following installs a fairly complete list of build dependencies on Debian Bullseye:
.. code-block:: none
apt install meson g++ \
libpcre3-dev \
libfmt-dev \
libpcre2-dev \
libmad0-dev libmpg123-dev libid3tag0-dev \
libflac-dev libvorbis-dev libopus-dev libogg-dev \
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
@ -110,6 +113,19 @@ The following command shows a list of compile-time options:
meson configure output/release
NB: Check the sysconfdir setting to determine where mpd will look for mpd.conf; if you expect mpd to look for /etc/mpd.conf the sysconfdir must be '/etc' (i.e., not 'etc' which will result in mpd looking for /usr/local/etc/mpd.conf):
.. code-block:: none
meson configure output/release |grep sysconfdir
If this is not /etc (or another path you wish to specify):
.. code-block:: none
$ meson configure output/release -Dsysconfdir='/etc' ; meson configure output/release |grep syscon
sysconfdir /etc Sysconf data directory
When everything is ready and configured, compile:
.. code-block:: none
@ -144,7 +160,7 @@ This section is about the latter.
You need:
* `mingw-w64 <http://mingw-w64.org/doku.php>`__
* `Meson 0.49.0 <http://mesonbuild.com/>`__ and `Ninja
* `Meson 0.56.0 <http://mesonbuild.com/>`__ and `Ninja
<https://ninja-build.org/>`__
* cmake
* pkg-config
@ -158,7 +174,9 @@ tarball and change into the directory. Then, instead of
mkdir -p output/win64
cd output/win64
../../win32/build.py --64
../../win32/build.py --64 \
--buildtype=debugoptimized -Db_ndebug=true \
-Dwrap_mode=forcefallback
This downloads various library sources, and then configures and builds
:program:`MPD` (for x64; to build a 32 bit binary, pass
@ -168,6 +186,11 @@ around. It is large, but easy to use. If you wish to have a small
mpd.exe with DLLs, you need to compile manually, without the
:file:`build.py` script.
The option ``-Dwrap_mode=forcefallback`` tells Meson to download and
cross-compile several libraries used by MPD instead of looking for
them on your computer.
Compiling for Android
---------------------
@ -176,8 +199,8 @@ Compiling for Android
You need:
* Android SDK
* `Android NDK r22 <https://developer.android.com/ndk/downloads>`_
* `Meson 0.49.0 <http://mesonbuild.com/>`__ and `Ninja
* `Android NDK r25b <https://developer.android.com/ndk/downloads>`_
* `Meson 0.56.0 <http://mesonbuild.com/>`__ and `Ninja
<https://ninja-build.org/>`__
* cmake
* pkg-config
@ -191,8 +214,10 @@ tarball and change into the directory. Then, instead of
mkdir -p output/android
cd output/android
../../android/build.py SDK_PATH NDK_PATH ABI
meson configure -Dandroid_debug_keystore=$HOME/.android/debug.keystore
../../android/build.py SDK_PATH NDK_PATH ABI \
--buildtype=debugoptimized -Db_ndebug=true \
-Dwrap_mode=forcefallback \
-Dandroid_debug_keystore=$HOME/.android/debug.keystore
ninja android/apk/mpd-debug.apk
:envvar:`SDK_PATH` is the absolute path where you installed the
@ -278,7 +303,7 @@ Configuring neighbor plugins
----------------------------
All neighbor plugins are disabled by default to avoid unwanted
overhead. To enable (and configure) a plugin, add a :code:`neighbor`
overhead. To enable (and configure) a plugin, add a :code:`neighbors`
block to :file:`mpd.conf`:
.. code-block:: none
@ -442,6 +467,11 @@ The following table lists the audio_output options valid for all plugins:
implement an external mixer, see :ref:`external_mixer`) or no mixer
(:samp:`none`). By default, the hardware mixer is used for
devices which support it, and none for the others.
* - **replay_gain_handler software|mixer|none**
- Specifies how :ref:`replay_gain` is applied. The default is
``software``, which uses an internal software volume control.
``mixer`` uses the configured (hardware) mixer control.
``none`` disables replay gain on this audio output.
* - **filters "name,...**"
- The specified configured filters are instantiated in the given
order. Each filter name refers to a ``filter`` block, see
@ -510,7 +540,7 @@ The following table lists the playlist_plugin options valid for all plugins:
* - Name
- Description
* - **plugin**
* - **name**
- The name of the plugin
* - **enabled yes|no**
- Allows you to disable a playlist plugin without recompiling. By default, all plugins are enabled.
@ -560,6 +590,90 @@ Sometimes, music needs to be resampled before it can be played; for example, CDs
Check the :ref:`resampler_plugins` reference for a list of resamplers
and how to configure them.
Volume Normalization Settings
-----------------------------
.. _replay_gain:
Replay Gain
^^^^^^^^^^^
The setting ``replaygain`` specifies whether MPD shall adjust the
volume of songs played using `ReplayGain
<https://wiki.hydrogenaud.io/index.php?title=Replaygain>`__ tags.
Setting this to ``album`` will adjust volume using the album's
ReplayGain tags, while setting it to ``track`` will adjust it using
the "track" ReplayGain tags. ``auto`` uses the track ReplayGain tags
if random play is activated otherwise the album ReplayGain
tags.
If ReplayGain is enabled, then the setting ``replaygain_preamp`` is
set to a value (in dB) between ``-15`` and ``15``. This is the gain
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
prevents `Bit-perfect playback`_). To use a hardware mixer, set
``replay_gain_handler`` to ``mixer`` in the ``audio_output`` section
(see :ref:`config_audio_output` for details).
Simple Volume Normalization
^^^^^^^^^^^^^^^^^^^^^^^^^^^
MPD implements a very simple volume normalization method which can be
enabled by setting ``volume_normalization`` to ``yes``. It supports
16 bit PCM only.
.. _crossfading:
Cross-Fading
------------
If ``crossfade`` is set to a positive number, then adjacent songs are
cross-faded by this number of seconds. This is a run-time setting
:ref:`which can be controlled by clients <command_crossfade>`,
e.g. with :program:`mpc`::
mpc crossfade 10
mpc crossfade 0
Zero means cross-fading is disabled.
Cross-fading is only possible if both songs have the same audio
format. At the cost of quality loss and higher CPU usage, you can
make sure this is always given by configuring
:ref:`audio_output_format`.
.. _mixramp:
MixRamp
^^^^^^^
MixRamp tags describe the loudness levels at start and end of a song
and can be used by MPD to find the best time to begin cross-fading.
MPD enables MixRamp if:
- Cross-fade is enabled
- :ref:`mixrampdelay <command_mixrampdelay>` is set to a positive
value, e.g.::
mpc mixrampdelay 1
- :ref:`mixrampdb <command_mixrampdb>` is set to a reasonable value,
e.g.::
mpc mixrampdb -17
- both songs have MixRamp tags
- both songs have the same audio format (or :ref:`audio_output_format`
is configured)
The `MixRamp <http://sourceforge.net/projects/mixramp>`__ tool can be
used to add MixRamp tags to your song files.
Client Connections
------------------
@ -625,13 +739,20 @@ By default, all clients are unauthenticated and have a full set of permissions.
- Allows reading of the database, displaying the current playlist, and current status of :program:`MPD`.
* - **add**
- Allows adding songs and loading playlists.
* - **player**
- Allows any player and queue manipulation (start/pause/stop
playback etc.).
* - **control**
- Allows all other player and playlist manipulations.
* - **admin**
- Allows database updates and allows shutting down :program:`MPD`.
- Allows manipulating outputs, stickers and partitions,
mounting/unmounting storage and shutting down :program:`MPD`.
:code:`local_permissions` may be used to assign other permissions to clients connecting on a local socket.
:code:`host_permissions` may be used to assign permissions to clients
with a certain IP address.
:code:`password` allows the client to send a password to gain other permissions. This option may be specified multiple times with different passwords.
Note that the :code:`password` option is not secure: passwords are sent in clear-text over the connection, and the client cannot verify the server's identity.
@ -641,6 +762,8 @@ Example:
.. code-block:: none
default_permissions "read"
host_permissions "192.168.0.100 read,add,control,admin"
host_permissions "2003:1234:4567::1 read,add,control,admin"
password "the_password@read,add,control"
password "the_admin_password@read,add,control,admin"
@ -688,6 +811,8 @@ The State File
- Specify the state file location. The parent directory must be writable by the :program:`MPD` user (+wx).
* - **state_file_interval SECONDS**
- Auto-save the state file this number of seconds after each state change. Defaults to 120 (2 minutes).
* - **restore_paused yes|no**
- If set to :samp:`yes`, then :program:`MPD` is put into pause mode instead of starting playback after startup. Default is :samp:`no`.
The Sticker Database
^^^^^^^^^^^^^^^^^^^^
@ -945,7 +1070,19 @@ The "music directory" is where you store your music files. :program:`MPD` stores
Depending on the size of your music collection and the speed of the storage, this can take a while.
To exclude a file from the update, create a file called :file:`.mpdignore` in its parent directory. Each line of that file may contain a list of shell wildcards. Matching files in the current directory and all subdirectories are excluded.
To exclude a file from the update, create a file called
:file:`.mpdignore` in its parent directory. Each line of that file
may contain a list of shell wildcards. Matching files (or
directories) in the current directory and all subdirectories are
excluded. Example::
*.opus
99*
Subject to pattern matching is the file/directory name. It is (not
yet) possible to match nested path names, e.g. something like
``foo/*.flac`` is not possible.
Mounting other storages into the music directory
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -985,6 +1122,15 @@ See :ref:`tags` for a list of supported tags.
The :ref:`metadata_to_use <metadata_to_use>` setting can be used to
enable or disable certain tags.
Note that :program:`MPD` may not necessarily read metadata itself,
instead relying on data reported by the decoder that was used to read
a file. For example, this is the case for the FFmpeg decoder: both
:program:`MPD` and FFmpeg need to support a given metadata format in
order for metadata to be picked up correctly.
Only if a decoder does not have metadata support will :program:`MPD`
attempt to parse a song's metadata itself.
The queue
---------
@ -1042,6 +1188,7 @@ Check list for bit-perfect playback:
* Disable sound processing inside ALSA by configuring a "hardware"
device (:samp:`hw:0,0` or similar).
* Don't use software volume (setting :code:`mixer_type`).
* Don't use :ref:`replay_gain`.
* Don't force :program:`MPD` to use a specific audio format (settings
:code:`format`, :ref:`audio_output_format <audio_output_format>`).
* Verify that you are really doing bit-perfect playback using :program:`MPD`'s verbose log and :file:`/proc/asound/card*/pcm*p/sub*/hw_params`. Some DACs can also indicate the audio format.
@ -1120,7 +1267,7 @@ Support
Getting Help
^^^^^^^^^^^^
The :program:`MPD` project runs a `forum <https://forum.musicpd.org/>`_ and an IRC channel (#mpd on Freenode) for requesting help. Visit the MPD help page for details on how to get help.
The :program:`MPD` project runs a `forum <https://forum.musicpd.org/>`_ and an IRC channel (#mpd on Libera.Chat) for requesting help. Visit the MPD help page for details on how to get help.
Common Problems
^^^^^^^^^^^^^^^
@ -1202,6 +1349,34 @@ Your bug report should contain:
* relevant portions of the log file (:option:`--verbose`)
* be clear about what you expect MPD to do, and what is actually happening
.. _profiler:
Too Much CPU Usage
^^^^^^^^^^^^^^^^^^
If you believe MPD consumes too much CPU, `write a bug report
<https://github.com/MusicPlayerDaemon/MPD/issues>`_ with a profiling
information.
On Linux, this can be obtained with :program:`perf` (on Debian,
installed the package :file:`linux-perf`), for example::
perf record -p `pidof mpd`
Run this command while MPD consumes much CPU, let it run for a minute
or so, and stop it by pressing ``Ctrl-C``. Then type::
perf report >mpd_perf.txt
Upload the output file to the bug report.
.. note::
This requires having debug symbols for MPD and all relevant
libraries. See :ref:`crash` for details.
.. _crash:
MPD crashes
^^^^^^^^^^^

@ -1,8 +1,8 @@
project(
'mpd',
['c', 'cpp'],
version: '0.22.7',
meson_version: '>= 0.49.0',
version: '0.23.13',
meson_version: '>= 0.56.0',
default_options: [
'c_std=c11',
'build.c_std=c11',
@ -10,9 +10,21 @@ project(
'build.cpp_std=c++17',
'warning_level=3',
# This is only here to build subprojects as static libraries; MPD
# itself doesn't ship any libraries.
'default_library=static',
# If we build those libraries as Meson subproject, they shall be
# linked statically into the MPD executable.
'expat:default_library=static',
'fmt:default_library=static',
'gtest:default_library=static',
'sqlite3:default_library=static',
'vorbis:default_library=static',
# Not interested in compiler warnings from subprojects.
'expat:werror=false',
'expat:warning_level=0',
'fmt:warning_level=0',
'gtest:warning_level=0',
'sqlite3:warning_level=0',
'vorbis:warning_level=0',
],
license: 'GPLv2+',
)
@ -24,15 +36,15 @@ c_compiler = meson.get_compiler('c')
if compiler.get_id() == 'gcc' and compiler.version().version_compare('<8')
warning('Your GCC version is too old. You need at least version 8.')
elif compiler.get_id() == 'clang' and compiler.version().version_compare('<5')
warning('Your clang version is too old. You need at least version 5.')
elif compiler.get_id() == 'clang' and compiler.version().version_compare('<7')
warning('Your clang version is too old. You need at least version 7.')
endif
version_conf = configuration_data()
version_conf.set_quoted('PACKAGE', meson.project_name())
version_conf.set_quoted('PACKAGE_NAME', meson.project_name())
version_conf.set_quoted('VERSION', meson.project_version())
version_conf.set_quoted('PROTOCOL_VERSION', '0.22.4')
version_conf.set_quoted('PROTOCOL_VERSION', '0.23.5')
configure_file(output: 'Version.h', configuration: version_conf)
conf = configuration_data()
@ -42,57 +54,66 @@ common_cppflags = [
'-D_GNU_SOURCE',
]
common_cflags = [
]
common_cxxflags = [
test_global_common_flags = [
'-fvisibility=hidden',
]
test_common_flags = [
'-Wvla',
'-Wdouble-promotion',
'-fvisibility=hidden',
'-ffast-math',
'-ftree-vectorize',
'-Wcast-qual',
'-Wdouble-promotion',
'-Wmissing-declarations',
'-Wshadow',
'-Wunused',
'-Wvla',
'-Wwrite-strings',
# clang specific warning options:
'-Wunreachable-code-aggressive',
'-Wused-but-marked-unused',
# suppress bogus GCC12 warnings in libfmt headers
'-Wno-stringop-overflow',
]
test_global_cxxflags = test_global_common_flags + [
]
test_global_cflags = test_global_common_flags + [
]
test_cxxflags = test_common_flags + [
'-fno-threadsafe-statics',
'-fmerge-all-constants',
'-Wmissing-declarations',
'-Wshadow',
'-Wpointer-arith',
'-Wcast-qual',
'-Wwrite-strings',
'-Wsign-compare',
'-Wcomma',
'-Wcomma-subscript',
'-Wextra-semi',
'-Wmismatched-tags',
'-Woverloaded-virtual',
'-Wsign-promo',
'-Wvolatile',
'-Wvirtual-inheritance',
# a vtable without a dtor is just fine
'-Wno-non-virtual-dtor',
# clang specific warning options:
'-Wcomma',
'-Wheader-hygiene',
'-Winconsistent-missing-destructor-override',
'-Wunreachable-code-break',
'-Wunused',
'-Wused-but-marked-unused',
'-Wno-non-virtual-dtor',
]
if compiler.get_id() == 'clang'
# Workaround for clang bug
# https://bugs.llvm.org/show_bug.cgi?id=32611
test_cxxflags += '-funwind-tables'
if compiler.get_id() != 'gcc' or compiler.version().version_compare('>=9')
# The GCC 8 implementation of this flag is buggy: it complains even
# if "final" is present, which implies "override".
test_cxxflags += '-Wsuggest-override'
endif
test_cflags = test_common_flags + [
'-Wmissing-prototypes',
'-Wshadow',
'-Wpointer-arith',
'-Wstrict-prototypes',
'-Wcast-qual',
'-Wwrite-strings',
'-pedantic',
]
test_ldflags = [
@ -104,11 +125,11 @@ test_ldflags = [
]
if get_option('buildtype') != 'debug'
test_cxxflags += [
test_global_cxxflags += [
'-ffunction-sections',
'-fdata-sections',
]
test_cflags += [
test_global_cflags += [
'-ffunction-sections',
'-fdata-sections',
]
@ -118,15 +139,20 @@ if get_option('buildtype') != 'debug'
endif
if get_option('fuzzer')
fuzzer_flags = ['-fsanitize=fuzzer,address,undefined']
fuzzer_flags = ['-fsanitize=fuzzer']
if get_option('b_sanitize') == 'none'
fuzzer_flags += ['-fsanitize=address,undefined']
endif
add_global_arguments(fuzzer_flags, language: 'cpp')
add_global_arguments(fuzzer_flags, language: 'c')
add_global_link_arguments(fuzzer_flags, language: 'cpp')
endif
add_global_arguments(common_cxxflags + compiler.get_supported_arguments(test_cxxflags), language: 'cpp')
add_global_arguments(common_cflags + c_compiler.get_supported_arguments(test_cflags), language: 'c')
add_global_link_arguments(compiler.get_supported_link_arguments(test_ldflags), language: 'cpp')
add_global_arguments(compiler.get_supported_arguments(test_global_cxxflags), language: 'cpp')
add_global_arguments(c_compiler.get_supported_arguments(test_global_cflags), language: 'c')
add_project_arguments(compiler.get_supported_arguments(test_cxxflags), language: 'cpp')
add_project_arguments(c_compiler.get_supported_arguments(test_cflags), language: 'c')
add_project_link_arguments(compiler.get_supported_link_arguments(test_ldflags), language: 'cpp')
is_linux = host_machine.system() == 'linux'
is_android = get_option('android_ndk') != ''
@ -179,7 +205,6 @@ enable_daemon = not is_windows and not is_android and get_option('daemon')
conf.set('ENABLE_DAEMON', enable_daemon)
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_FNMATCH', compiler.has_function('fnmatch'))
@ -193,17 +218,6 @@ conf.set('HAVE_STRCASESTR', compiler.has_function('strcasestr'))
conf.set('HAVE_PRCTL', is_linux)
conf.set('USE_EVENTFD', is_linux and get_option('eventfd'))
conf.set('USE_SIGNALFD', is_linux and get_option('signalfd'))
if is_windows
conf.set('USE_WINSELECT', true)
elif is_linux and get_option('epoll')
conf.set('USE_EPOLL', true)
else
conf.set('USE_POLL', true)
endif
if not get_option('syslog').disabled()
if compiler.has_function('syslog')
conf.set('HAVE_SYSLOG', true)
@ -234,23 +248,35 @@ if boost_dep.version() == '1.67'
warning('Your Boost version 1.67 is known to be buggy, and the MPD build will fail. Please upgrade to Boost 1.68 or later.')
endif
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',
'src/Log.cxx',
'src/LogBackend.cxx',
include_directories: inc,
dependencies: fmt_dep,
)
log_dep = declare_dependency(
link_with: log,
dependencies: fmt_dep,
)
sources = [
version_cxx,
'src/Main.cxx',
'src/protocol/ArgParser.cxx',
'src/protocol/Result.cxx',
'src/command/CommandError.cxx',
'src/command/PositionArg.cxx',
'src/command/AllCommands.cxx',
'src/command/QueueCommands.cxx',
'src/command/TagCommands.cxx',
@ -265,7 +291,6 @@ sources = [
'src/command/CommandListBuilder.cxx',
'src/Idle.cxx',
'src/IdleFlags.cxx',
'src/decoder/Domain.cxx',
'src/decoder/Thread.cxx',
'src/decoder/Control.cxx',
'src/decoder/Bridge.cxx',
@ -334,7 +359,7 @@ sources = [
'src/TagStream.cxx',
'src/TagAny.cxx',
'src/TimePrint.cxx',
'src/mixer/Volume.cxx',
'src/mixer/Memento.cxx',
'src/PlaylistFile.cxx',
]
@ -364,6 +389,7 @@ endif
if enable_database
sources += [
'src/storage/StorageState.cxx',
'src/queue/PlaylistUpdate.cxx',
'src/command/StorageCommands.cxx',
'src/command/DatabaseCommands.cxx',
@ -396,6 +422,7 @@ subdir('src/lib/gcrypt')
subdir('src/lib/nfs')
subdir('src/lib/oss')
subdir('src/lib/pcre')
subdir('src/lib/pipewire')
subdir('src/lib/pulse')
subdir('src/lib/sndio')
subdir('src/lib/sqlite')
@ -405,6 +432,8 @@ subdir('src/lib/yajl')
subdir('src/lib/crypto')
subdir('src/zeroconf')
subdir('src/fs')
subdir('src/config')
subdir('src/tag')
@ -420,7 +449,6 @@ subdir('src/decoder')
subdir('src/encoder')
subdir('src/song')
subdir('src/playlist')
subdir('src/zeroconf')
if curl_dep.found()
sources += 'src/RemoteTagCache.cxx'
@ -536,6 +564,7 @@ mpd = build_target(
zeroconf_dep,
more_deps,
chromaprint_dep,
fmt_dep,
],
link_args: link_args,
build_by_default: not get_option('fuzzer'),

@ -62,7 +62,10 @@ option('dsd', type: 'boolean', value: true, description: 'Support the DSD audio
#
option('database', type: 'boolean', value: true, description: 'enable support for the music database')
option('upnp', type: 'feature', description: 'UPnP client support')
option('upnp', type: 'combo',
choices: ['auto', 'pupnp', 'npupnp', 'disabled'],
value: 'auto',
description: 'UPnP client support')
option('libmpdclient', type: 'feature', description: 'libmpdclient support (for the proxy database plugin)')
#
@ -104,7 +107,6 @@ option('smbclient', type: 'feature', value: 'disabled', description: 'SMB suppor
option('qobuz', type: 'feature', description: 'Qobuz client')
option('soundcloud', type: 'feature', description: 'SoundCloud client')
option('tidal', type: 'feature', description: 'Tidal client')
#
# Archive plugins
@ -135,6 +137,7 @@ option('gme', type: 'feature', description: 'Game Music Emulator decoder plugin'
option('mad', type: 'feature', description: 'MP3 decoder using libmad')
option('mikmod', type: 'feature', description: 'MikMod decoder plugin')
option('modplug', type: 'feature', description: 'Modplug decoder plugin')
option('openmpt', type: 'feature', description: 'OpenMPT decoder plugin')
option('mpcdec', type: 'feature', description: 'Musepack decoder plugin')
option('mpg123', type: 'feature', description: 'MP3 decoder using libmpg123')
option('opus', type: 'feature', description: 'Opus decoder plugin')
@ -174,9 +177,11 @@ option('jack', type: 'feature', description: 'JACK output plugin')
option('openal', type: 'feature', description: 'OpenAL output plugin')
option('oss', type: 'feature', description: 'Open Sound System support')
option('pipe', type: 'boolean', value: true, description: 'Pipe output plugin')
option('pipewire', type: 'feature', description: 'PipeWire support')
option('pulse', type: 'feature', description: 'PulseAudio support')
option('recorder', type: 'boolean', value: true, description: 'Recorder output plugin')
option('shout', type: 'feature', description: 'Shoutcast streaming support using libshout')
option('snapcast', type: 'boolean', value: true, description: 'Snapcast output plugin')
option('sndio', type: 'feature', description: 'sndio output plugin')
option('solaris_output', type: 'feature', description: 'Solaris /dev/audio support')

@ -45,20 +45,33 @@ class AutotoolsProject(MakeProject):
'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
'LIBS=' + toolchain.libs + ' ' + self.libs,
'AR=' + toolchain.ar,
'ARFLAGS=' + toolchain.arflags,
'RANLIB=' + toolchain.ranlib,
'STRIP=' + toolchain.strip,
'--host=' + toolchain.arch,
'--prefix=' + toolchain.install_prefix,
'--enable-silent-rules',
'--disable-silent-rules',
] + self.configure_args
subprocess.check_call(configure, cwd=build, env=toolchain.env)
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
return build
def build(self, toolchain):
def _build(self, toolchain):
build = self.configure(toolchain)
if self.subdirs is not None:
for subdir in self.subdirs:
MakeProject.build(self, toolchain, os.path.join(build, subdir))
self.build_make(toolchain, os.path.join(build, subdir))
else:
MakeProject.build(self, toolchain, build)
self.build_make(toolchain, build)

@ -12,7 +12,7 @@ class BoostProject(Project):
name='boost', version=version,
**kwargs)
def build(self, toolchain):
def _build(self, toolchain):
src = self.unpack(toolchain)
# install the headers manually; don't build any library

@ -1,45 +1,115 @@
import os
import re
import subprocess
from build.project import Project
def configure(toolchain, src, build, args=()):
def __write_cmake_compiler(f, language, compiler):
s = compiler.split(' ', 1)
if len(s) == 2:
print(f'set(CMAKE_{language}_COMPILER_LAUNCHER {s[0]})', file=f)
compiler = s[1]
print(f'set(CMAKE_{language}_COMPILER {compiler})', file=f)
def __write_cmake_toolchain_file(f, toolchain):
if '-darwin' in toolchain.actual_arch:
cmake_system_name = 'Darwin'
elif toolchain.is_windows:
cmake_system_name = 'Windows'
else:
cmake_system_name = 'Linux'
f.write(f"""
set(CMAKE_SYSTEM_NAME {cmake_system_name})
set(CMAKE_SYSTEM_PROCESSOR {toolchain.actual_arch.split('-', 1)[0]})
set(CMAKE_C_COMPILER_TARGET {toolchain.actual_arch})
set(CMAKE_CXX_COMPILER_TARGET {toolchain.actual_arch})
set(CMAKE_C_FLAGS_INIT "{toolchain.cflags} {toolchain.cppflags}")
set(CMAKE_CXX_FLAGS_INIT "{toolchain.cxxflags} {toolchain.cppflags}")
""")
__write_cmake_compiler(f, 'C', toolchain.cc)
__write_cmake_compiler(f, 'CXX', toolchain.cxx)
if cmake_system_name == 'Darwin':
# 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)
""")
def configure(toolchain, src, build, args=(), env=None):
cross_args = []
if toolchain.is_windows:
cross_args.append('-DCMAKE_SYSTEM_NAME=Windows')
cross_args.append('-DCMAKE_RC_COMPILER=' + 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 = [
'cmake',
src,
'-DCMAKE_TOOLCHAIN_FILE=' + cmake_toolchain_file,
'-DCMAKE_INSTALL_PREFIX=' + toolchain.install_prefix,
'-DCMAKE_BUILD_TYPE=release',
'-DCMAKE_C_COMPILER=' + toolchain.cc,
'-DCMAKE_CXX_COMPILER=' + toolchain.cxx,
'-DCMAKE_C_FLAGS=' + toolchain.cflags + ' ' + toolchain.cppflags,
'-DCMAKE_CXX_FLAGS=' + toolchain.cxxflags + ' ' + toolchain.cppflags,
'-GNinja',
] + cross_args + args
subprocess.check_call(configure, env=toolchain.env, cwd=build)
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):
def __init__(self, url, md5, installed, configure_args=[],
windows_configure_args=[],
env=None,
**kwargs):
Project.__init__(self, url, md5, installed, **kwargs)
self.configure_args = configure_args
self.windows_configure_args = windows_configure_args
self.env = env
def configure(self, toolchain):
src = self.unpack(toolchain)
build = self.make_build_path(toolchain)
configure(toolchain, src, build, self.configure_args)
configure_args = self.configure_args
if toolchain.is_windows:
configure_args = configure_args + self.windows_configure_args
configure(toolchain, src, build, configure_args, self.env)
return build
def build(self, toolchain):
def _build(self, toolchain):
build = self.configure(toolchain)
subprocess.check_call(['ninja', 'install'],
subprocess.check_call(['ninja', '-v', 'install'],
cwd=build, env=toolchain.env)

@ -10,7 +10,7 @@ class FfmpegProject(Project):
self.configure_args = configure_args
self.cppflags = cppflags
def build(self, toolchain):
def _build(self, toolchain):
src = self.unpack(toolchain)
build = self.make_build_path(toolchain)

@ -26,7 +26,7 @@ class JackProject(Project):
base='jack2-' + self.version,
**kwargs)
def build(self, toolchain):
def _build(self, toolchain):
src = self.unpack(toolchain)
includes = ['jack.h', 'ringbuffer.h', 'systemdeps.h', 'transport.h', 'types.h', 'weakmacros.h']

@ -12,34 +12,22 @@ from build.boost import BoostProject
from build.jack import JackProject
libmpdclient = MesonProject(
'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.19.tar.xz',
'158aad4c2278ab08e76a3f2b0166c99b39fae00ee17231bd225c5a36e977a189',
'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.20.tar.xz',
'18793f68e939c3301e34d8fcadea1f7daa24143941263cecadb80126194e277d',
'lib/libmpdclient.a',
)
libogg = AutotoolsProject(
'http://downloads.xiph.org/releases/ogg/libogg-1.3.4.tar.xz',
'c163bc12bc300c401b6aa35907ac682671ea376f13ae0969a220f7ddf71893fe',
libogg = CmakeProject(
'http://downloads.xiph.org/releases/ogg/libogg-1.3.5.tar.xz',
'c4d91be36fc8e54deae7575241e03f4211eb102afb3fc0775fbbc1b740016705',
'lib/libogg.a',
[
'--disable-shared', '--enable-static',
'-DBUILD_SHARED_LIBS=OFF',
'-DINSTALL_DOCS=OFF',
'-DINSTALL_CMAKE_PACKAGE_MODULE=OFF',
],
)
libvorbis = AutotoolsProject(
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz',
'b33cc4934322bcbf6efcbacf49e3ca01aadbea4114ec9589d1b1e9d20f72954b',
'lib/libvorbis.a',
[
'--disable-shared', '--enable-static',
],
edits={
# this option is not understood by clang
'configure': lambda data: data.replace('-mno-ieee-fp', ' '),
}
)
opus = AutotoolsProject(
'https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz',
'65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d',
@ -55,20 +43,22 @@ opus = AutotoolsProject(
)
flac = AutotoolsProject(
'http://downloads.xiph.org/releases/flac/flac-1.3.3.tar.xz',
'213e82bd716c9de6db2f98bcadbc4c24c7e2efe8c75939a1a84e28539c4e1748',
'http://downloads.xiph.org/releases/flac/flac-1.4.2.tar.xz',
'e322d58a1f48d23d9dd38f432672865f6f79e73a6f9cc5a5f57fcaa83eb5a8e4',
'lib/libFLAC.a',
[
'--disable-shared', '--enable-static',
'--disable-stack-smash-protection',
'--disable-xmms-plugin', '--disable-cpplibs',
'--disable-doxygen-docs',
'--disable-programs',
],
subdirs=['include', 'src/libFLAC'],
)
zlib = ZlibProject(
'http://zlib.net/zlib-1.2.11.tar.xz',
'4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066',
'http://zlib.net/zlib-1.2.13.tar.xz',
'd14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98',
'lib/libz.a',
)
@ -123,18 +113,32 @@ libmodplug = AutotoolsProject(
],
)
libopenmpt = AutotoolsProject(
'https://lib.openmpt.org/files/libopenmpt/src/libopenmpt-0.6.6+release.autotools.tar.gz',
'6ddb9e26a430620944891796fefb1bbb38bd9148f6cfc558810c0d3f269876c7',
'lib/libopenmpt.a',
[
'--disable-shared', '--enable-static',
'--disable-openmpt123',
'--disable-examples',
'--disable-tests',
'--disable-doxygen-doc',
'--without-mpg123', '--without-ogg', '--without-vorbis', '--without-vorbisfile',
'--without-portaudio', '--without-portaudiocpp', '--without-sndfile',
'--without-flac',
],
base='libopenmpt-0.6.6+release.autotools',
)
wildmidi = CmakeProject(
'https://codeload.github.com/Mindwerks/wildmidi/tar.gz/wildmidi-0.4.3',
'498e5a96455bb4b91b37188ad6dcb070824e92c44f5ed452b90adbaec8eef3c5',
'https://github.com/Mindwerks/wildmidi/releases/download/wildmidi-0.4.5/wildmidi-0.4.5.tar.gz',
'd5e7bef00a7aa47534a53d43b1265f8d3d27f6a28e7f563c1cdf02ff4fa35b99',
'lib/libWildMidi.a',
[
'-DBUILD_SHARED_LIBS=OFF',
'-DWANT_PLAYER=OFF',
'-DWANT_STATIC=ON',
],
base='wildmidi-wildmidi-0.4.3',
name='wildmidi',
version='0.4.3',
)
gme = CmakeProject(
@ -150,8 +154,8 @@ gme = CmakeProject(
)
ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-4.4.tar.xz',
'06b10a183ce5371f915c6bb15b7b1fffbe046e8275099c96affc29e17645d909',
'http://ffmpeg.org/releases/ffmpeg-6.0.tar.xz',
'57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082',
'lib/libavcodec.a',
[
'--disable-shared', '--enable-static',
@ -165,17 +169,21 @@ ffmpeg = FfmpegProject(
'--disable-swscale',
'--disable-postproc',
'--disable-avfilter',
'--disable-lzo',
'--disable-faan',
'--disable-pixelutils',
'--disable-network',
'--disable-encoders',
'--disable-hwaccels',
'--disable-muxers',
'--disable-protocols',
'--disable-devices',
'--disable-filters',
'--disable-v4l2_m2m',
'--disable-sdl2',
'--disable-vulkan',
'--disable-xlib',
'--disable-parser=bmp',
'--disable-parser=cavsvideo',
'--disable-parser=dvbsub',
@ -188,17 +196,22 @@ ffmpeg = FfmpegProject(
'--disable-parser=h263',
'--disable-parser=h264',
'--disable-parser=hevc',
'--disable-parser=jpeg2000',
'--disable-parser=mjpeg',
'--disable-parser=mlp',
'--disable-parser=mpeg4video',
'--disable-parser=mpegvideo',
'--disable-parser=opus',
'--disable-parser=qoi',
'--disable-parser=rv30',
'--disable-parser=rv40',
'--disable-parser=vc1',
'--disable-parser=vp3',
'--disable-parser=vp8',
'--disable-parser=vp9',
'--disable-parser=png',
'--disable-parser=pnm',
'--disable-parser=webp',
'--disable-parser=xma',
'--disable-demuxer=aqtitle',
@ -214,6 +227,42 @@ ffmpeg = FfmpegProject(
'--disable-demuxer=h264',
'--disable-demuxer=ico',
'--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=lrc',
'--disable-demuxer=microdvd',
@ -236,6 +285,7 @@ ffmpeg = FfmpegProject(
'--disable-demuxer=tedcaptions',
'--disable-demuxer=vobsub',
'--disable-demuxer=vplayer',
'--disable-demuxer=webm_dash_manifest',
'--disable-demuxer=webvtt',
'--disable-demuxer=yuv4mpegpipe',
@ -265,78 +315,179 @@ ffmpeg = FfmpegProject(
'--disable-decoder=qdmc',
# 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=asv1',
'--disable-decoder=asv2',
'--disable-decoder=apng',
'--disable-decoder=aura',
'--disable-decoder=aura2',
'--disable-decoder=avrn',
'--disable-decoder=avrp',
'--disable-decoder=avui',
'--disable-decoder=ayuv',
'--disable-decoder=bethsoftvid',
'--disable-decoder=bfi',
'--disable-decoder=bink',
'--disable-decoder=bintext',
'--disable-decoder=bitpacked',
'--disable-decoder=bmp',
'--disable-decoder=bmv_video',
'--disable-decoder=brender_pix',
'--disable-decoder=c93',
'--disable-decoder=cavs',
'--disable-decoder=ccaption',
'--disable-decoder=cdgraphics',
'--disable-decoder=cdtoons',
'--disable-decoder=cdxl',
'--disable-decoder=cfhd',
'--disable-decoder=cinepak',
'--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=dnxhd',
'--disable-decoder=dpx',
'--disable-decoder=dsicinvideo',
'--disable-decoder=dvbsub',
'--disable-decoder=dvdsub',
'--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=ffv1',
'--disable-decoder=ffvhuff',
'--disable-decoder=ffwavesynth',
'--disable-decoder=fic',
'--disable-decoder=fits',
'--disable-decoder=flashsv',
'--disable-decoder=flashsv2',
'--disable-decoder=flic',
'--disable-decoder=flv',
'--disable-decoder=fmvc',
'--disable-decoder=fraps',
'--disable-decoder=fourxm',
'--disable-decoder=frwu',
'--disable-decoder=g2m',
'--disable-decoder=gdv',
'--disable-decoder=gem',
'--disable-decoder=gif',
'--disable-decoder=h261',
'--disable-decoder=h263',
'--disable-decoder=h263i',
'--disable-decoder=h263p',
'--disable-decoder=h264',
'--disable-decoder=hap',
'--disable-decoder=hevc',
'--disable-decoder=hnm4_video',
'--disable-decoder=hq_hqa',
'--disable-decoder=hqx',
'--disable-decoder=huffyuv',
'--disable-decoder=hymt',
'--disable-decoder=idcin',
'--disable-decoder=idf',
'--disable-decoder=iff_ilbm',
'--disable-decoder=imm4',
'--disable-decoder=indeo2',
'--disable-decoder=indeo3',
'--disable-decoder=indeo4',
'--disable-decoder=indeo5',
'--disable-decoder=interplay_video',
'--disable-decoder=ipu',
'--disable-decoder=jacosub',
'--disable-decoder=jpeg2000',
'--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=mimic',
'--disable-decoder=mjpeg',
'--disable-decoder=mmvideo',
'--disable-decoder=mpl2',
'--disable-decoder=mobiclip',
'--disable-decoder=motionpixels',
'--disable-decoder=movtext',
'--disable-decoder=mpeg1video',
'--disable-decoder=mpeg2video',
'--disable-decoder=mpeg4',
'--disable-decoder=mpegvideo',
'--disable-decoder=msa1',
'--disable-decoder=mscc',
'--disable-decoder=msmpeg4_crystalhd',
'--disable-decoder=msmpeg4v1',
'--disable-decoder=msmpeg4v2',
'--disable-decoder=msmpeg4v3',
'--disable-decoder=msp2',
'--disable-decoder=msrle',
'--disable-decoder=mss1',
'--disable-decoder=msvideo1',
'--disable-decoder=mszh',
'--disable-decoder=mts2',
'--disable-decoder=mv30',
'--disable-decoder=mvc1',
'--disable-decoder=mvc2',
'--disable-decoder=mvdv',
'--disable-decoder=mvha',
'--disable-decoder=mwsc',
'--disable-decoder=notchlc',
'--disable-decoder=nuv',
'--disable-decoder=on2avc',
'--disable-decoder=paf_video',
'--disable-decoder=pam',
'--disable-decoder=pbm',
'--disable-decoder=pcx',
'--disable-decoder=pgm',
'--disable-decoder=pgmyuv',
'--disable-decoder=pgssub',
'--disable-decoder=pgx',
'--disable-decoder=phm',
'--disable-decoder=photocd',
'--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=qoi',
'--disable-decoder=qpeg',
'--disable-decoder=qtrle',
'--disable-decoder=rawvideo',
'--disable-decoder=r10k',
'--disable-decoder=r210',
'--disable-decoder=rasc',
'--disable-decoder=realtext',
'--disable-decoder=rl2',
'--disable-decoder=rpza',
'--disable-decoder=roq',
'--disable-decoder=roq_dpcm',
'--disable-decoder=rscc',
@ -345,90 +496,150 @@ ffmpeg = FfmpegProject(
'--disable-decoder=rv30',
'--disable-decoder=rv40',
'--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=simbiosis_imx',
'--disable-decoder=smc',
'--disable-decoder=snow',
'--disable-decoder=speedhq',
'--disable-decoder=srgc',
'--disable-decoder=srt',
'--disable-decoder=ssa',
'--disable-decoder=stl',
'--disable-decoder=subrip',
'--disable-decoder=subviewer',
'--disable-decoder=subviewer1',
'--disable-decoder=sunrast',
'--disable-decoder=svq1',
'--disable-decoder=svq3',
'--disable-decoder=targa',
'--disable-decoder=targa_y216',
'--disable-decoder=text',
'--disable-decoder=tiff',
'--disable-decoder=tiertexseqvideo',
'--disable-decoder=tmv',
'--disable-decoder=truemotion1',
'--disable-decoder=truemotion2',
'--disable-decoder=truemotion2rt',
'--disable-decoder=tscc',
'--disable-decoder=tscc2',
'--disable-decoder=twinvq',
'--disable-decoder=txd',
'--disable-decoder=ulti',
'--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=vcr1',
'--disable-decoder=vmdvideo',
'--disable-decoder=vmnc',
'--disable-decoder=vp3',
'--disable-decoder=vp5',
'--disable-decoder=vp6',
'--disable-decoder=vp7',
'--disable-decoder=vp8',
'--disable-decoder=vp9',
'--disable-decoder=vplayer',
'--disable-decoder=vqa',
'--disable-decoder=webvtt',
'--disable-decoder=wcmv',
'--disable-decoder=wmv1',
'--disable-decoder=wmv2',
'--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=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(
'https://www.openssl.org/source/openssl-3.0.0-alpha16.tar.gz',
'08ce8244b59d75f40f91170dfcb012bf25309cdcb1fef9502e39d694f883d1d1',
'https://www.openssl.org/source/openssl-3.1.0.tar.gz',
'aaa925ad9828745c4cad9d9efeb273deca820f2cdcf2c3ac7d7c1212b7c497b4',
'include/openssl/ossl_typ.h',
)
curl = AutotoolsProject(
'https://curl.se/download/curl-7.76.1.tar.xz',
'64bb5288c39f0840c07d077e30d9052e1cbb9fa6c2dc52523824cc859e679145',
curl = CmakeProject(
'https://curl.se/download/curl-8.0.1.tar.xz',
'0a381cd82f4d00a9a334438b8ca239afea5bfefcfa9a1025f2bf118e79e0b5f0',
'lib/libcurl.a',
[
'--disable-shared', '--enable-static',
'--disable-debug',
'--enable-http',
'--enable-ipv6',
'--disable-ftp', '--disable-file',
'--disable-ldap', '--disable-ldaps',
'--disable-rtsp', '--disable-proxy', '--disable-dict', '--disable-telnet',
'--disable-tftp', '--disable-pop3', '--disable-imap', '--disable-smtp',
'--disable-smb',
'--disable-gopher',
'--disable-manual',
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
'--disable-crypto-auth', '--disable-ntlm-wb', '--disable-tls-srp', '--disable-cookies',
'--disable-doh',
'--disable-mime',
'--disable-netrc',
'--disable-progress-meter',
'--disable-alt-svc',
'--without-gnutls', '--without-nss', '--without-libssh2',
# native Windows SSL/TLS support, option ignored on non-Windows builds
'--with-schannel',
'-DBUILD_CURL_EXE=OFF',
'-DBUILD_SHARED_LIBS=OFF',
'-DCURL_DISABLE_LDAP=ON',
'-DCURL_DISABLE_TELNET=ON',
'-DCURL_DISABLE_DICT=ON',
'-DCURL_DISABLE_FILE=ON',
'-DCURL_DISABLE_FTP=ON',
'-DCURL_DISABLE_TFTP=ON',
'-DCURL_DISABLE_LDAPS=ON',
'-DCURL_DISABLE_RTSP=ON',
'-DCURL_DISABLE_PROXY=ON',
'-DCURL_DISABLE_POP3=ON',
'-DCURL_DISABLE_IMAP=ON',
'-DCURL_DISABLE_SMTP=ON',
'-DCURL_DISABLE_GOPHER=ON',
'-DCURL_DISABLE_COOKIES=ON',
'-DCURL_DISABLE_CRYPTO_AUTH=ON',
'-DCURL_DISABLE_ALTSVC=ON',
'-DCMAKE_USE_LIBSSH2=OFF',
'-DCURL_WINDOWS_SSPI=OFF',
'-DCURL_DISABLE_NTLM=ON',
'-DBUILD_TESTING=OFF',
],
windows_configure_args=[
'-DCURL_USE_SCHANNEL=ON',
],
patches='src/lib/curl/patches',
)
libexpat = AutotoolsProject(
'https://github.com/libexpat/libexpat/releases/download/R_2_2_9/expat-2.2.9.tar.bz2',
'f1063084dc4302a427dabcca499c8312b3a32a29b7d2506653ecc8f950a9a237',
'lib/libexpat.a',
[
'--disable-shared', '--enable-static',
'--without-docbook',
],
)
libnfs = AutotoolsProject(
'https://github.com/sahlberg/libnfs/archive/libnfs-4.0.0.tar.gz',
'6ee77e9fe220e2d3e3b1f53cfea04fb319828cc7dbb97dd9df09e46e901d797d',
'https://github.com/sahlberg/libnfs/archive/libnfs-5.0.2.tar.gz',
'637e56643b19da9fba98f06847788c4dad308b723156a64748041035dcdf9bd3',
'lib/libnfs.a',
[
'--disable-shared', '--enable-static',
@ -439,8 +650,7 @@ libnfs = AutotoolsProject(
'--disable-utils', '--disable-examples',
],
base='libnfs-libnfs-4.0.0',
patches='src/lib/nfs/patches',
base='libnfs-libnfs-5.0.2',
autoreconf=True,
)
@ -451,7 +661,7 @@ jack = JackProject(
)
boost = BoostProject(
'https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/boost_1_76_0.tar.bz2',
'f0397ba6e982c4450f27bf32a2a83292aba035b827a5623a14636ea583318c41',
'https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.bz2',
'71feeed900fbccca04a3b4f2f84a7c217186f28a940ed8b7ed4725986baf99fa',
'include/boost/version.hpp',
)

@ -1,4 +1,4 @@
import subprocess
import subprocess, multiprocessing
from build.project import Project
@ -10,7 +10,12 @@ class MakeProject(Project):
self.install_target = install_target
def get_simultaneous_jobs(self):
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):
return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
@ -19,10 +24,10 @@ class MakeProject(Project):
return ['--quiet', self.install_target]
def make(self, toolchain, wd, args):
subprocess.check_call(['/usr/bin/make'] + args,
subprocess.check_call(['make'] + args,
cwd=wd, env=toolchain.env)
def build(self, toolchain, wd, install=True):
def build_make(self, toolchain, wd, install=True):
self.make(toolchain, wd, self.get_make_args(toolchain))
if install:
self.make(toolchain, wd, self.get_make_install_args(toolchain))

@ -1,4 +1,6 @@
import os.path, subprocess, sys
import os
import subprocess
import platform
from build.project import Project
@ -34,56 +36,58 @@ def make_cross_file(toolchain):
path = os.path.join(toolchain.build_path, 'meson.cross')
os.makedirs(toolchain.build_path, exist_ok=True)
with open(path, 'w') as f:
f.write("""
f.write(f"""
[binaries]
c = '%s'
cpp = '%s'
ar = '%s'
strip = '%s'
pkgconfig = '%s'
%s
c = '{toolchain.cc}'
cpp = '{toolchain.cxx}'
ar = '{toolchain.ar}'
strip = '{toolchain.strip}'
pkgconfig = '{toolchain.pkg_config}'
""")
if toolchain.is_windows and platform.system() != 'Windows':
f.write(f"windres = '{toolchain.windres}'\n")
# Run unit tests with WINE when cross-building for Windows
print("exe_wrapper = 'wine'", file=f)
f.write(f"""
[properties]
root = '%s'
c_args = %s
c_link_args = %s
cpp_args = %s
cpp_link_args = %s
root = '{toolchain.install_prefix}'
""")
if 'android' in toolchain.arch:
f.write("""
# Keep Meson from executing Android-x86 test binariees
needs_exe_wrapper = true
""")
f.write(f"""
[built-in options]
c_args = {repr((toolchain.cppflags + ' ' + toolchain.cflags).split())}
c_link_args = {repr(toolchain.ldflags.split() + toolchain.libs.split())}
cpp_args = {repr((toolchain.cppflags + ' ' + toolchain.cxxflags).split())}
cpp_link_args = {repr(toolchain.ldflags.split() + toolchain.libs.split())}
""")
f.write(f"""
[host_machine]
system = '%s'
cpu_family = '%s'
cpu = '%s'
endian = '%s'
""" % (toolchain.cc, toolchain.cxx, toolchain.ar, toolchain.strip,
toolchain.pkg_config,
windres,
toolchain.install_prefix,
repr((toolchain.cppflags + ' ' + toolchain.cflags).split()),
repr(toolchain.ldflags.split() + toolchain.libs.split()),
repr((toolchain.cppflags + ' ' + toolchain.cxxflags).split()),
repr(toolchain.ldflags.split() + toolchain.libs.split()),
system, cpu_family, cpu, endian))
system = '{system}'
cpu_family = '{cpu_family}'
cpu = '{cpu}'
endian = '{endian}'
""")
return path
def configure(toolchain, src, build, args=()):
cross_file = make_cross_file(toolchain)
configure = [
'meson',
src, build,
'meson', 'setup',
build, src,
'--prefix', toolchain.install_prefix,
# this is necessary because Meson uses Debian's build machine
# MultiArch path (e.g. "lib/x86_64-linux-gnu") for cross
# builds, which is obviously wrong
'--libdir', 'lib',
'--buildtype', 'plain',
'--default-library=static',
@ -110,7 +114,7 @@ class MesonProject(Project):
configure(toolchain, src, build, self.configure_args)
return build
def build(self, toolchain):
def _build(self, toolchain):
build = self.configure(toolchain)
subprocess.check_call(['ninja', 'install'],
subprocess.check_call(['ninja', '-v', 'install'],
cwd=build, env=toolchain.env)

@ -17,7 +17,13 @@ class OpenSSLProject(MakeProject):
'build_libs',
]
def build(self, toolchain):
def get_make_install_args(self, toolchain):
# OpenSSL's Makefile runs "ranlib" during installation
return MakeProject.get_make_install_args(self, toolchain) + [
'RANLIB=' + toolchain.ranlib,
]
def _build(self, toolchain):
src = self.unpack(toolchain, out_of_tree=False)
# OpenSSL has a weird target architecture scheme with lots of
@ -52,4 +58,4 @@ class OpenSSLProject(MakeProject):
openssl_arch,
'--prefix=' + toolchain.install_prefix],
cwd=src, env=toolchain.env)
MakeProject.build(self, toolchain, src)
self.build_make(toolchain, src)

@ -14,13 +14,14 @@ class Project:
if base is None:
basename = os.path.basename(url)
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)
else:
self.base = base
if name is None or version is None:
m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?[\d.]*(?:-alpha\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 version is None: version = m.group(2)
@ -55,8 +56,8 @@ class Project:
parent_path = toolchain.src_path
else:
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:
push_all(toolchain, path, self.patches)
@ -71,11 +72,16 @@ class Project:
return path
def make_build_path(self, toolchain):
def make_build_path(self, toolchain, lazy=False):
path = os.path.join(toolchain.build_path, self.base)
if lazy and os.path.isdir(path):
return path
try:
shutil.rmtree(path)
except FileNotFoundError:
pass
os.makedirs(path, exist_ok=True)
return path
def build(self, toolchain):
self._build(toolchain)

@ -1,14 +1,16 @@
import os, shutil, subprocess
def untar(tarball_path, parent_path, base):
def untar(tarball_path, parent_path, base, lazy=False):
path = os.path.join(parent_path, base)
if lazy and os.path.isdir(path):
return path
try:
shutil.rmtree(path)
except FileNotFoundError:
pass
os.makedirs(parent_path, exist_ok=True)
try:
subprocess.check_call(['/bin/tar', 'xfC', tarball_path, parent_path])
subprocess.check_call(['tar', 'xfC', tarball_path, parent_path])
except FileNotFoundError:
import tarfile
tar = tarfile.open(tarball_path)

@ -31,6 +31,8 @@ def guess_digest_algorithm(digest):
return hashlib.sha1
elif l == 64:
return hashlib.sha256
elif l == 128:
return hashlib.sha512
else:
return None

@ -1,22 +1,32 @@
import os.path, subprocess
import subprocess
from build.project import Project
from build.makeproject import MakeProject
class ZlibProject(Project):
class ZlibProject(MakeProject):
def __init__(self, url, md5, installed,
**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):
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):
return [
'RANLIB=' + toolchain.ranlib,
self.install_target
]
def _build(self, toolchain):
src = self.unpack(toolchain, out_of_tree=False)
subprocess.check_call(['/usr/bin/make', '--quiet',
'-f', 'win32/Makefile.gcc',
'PREFIX=' + toolchain.arch + '-',
'-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)
subprocess.check_call(['./configure', '--prefix=' + toolchain.install_prefix, '--static'],
cwd=src, env=toolchain.env)
self.build_make(toolchain, src)

@ -37,6 +37,7 @@
#include "fs/Traits.hxx"
#include "fs/FileSystem.hxx"
#include "fs/StandardDirectory.hxx"
#include "event/Features.h"
#include "io/uring/Features.h"
#include "util/Domain.hxx"
#include "util/OptionDef.hxx"
@ -85,6 +86,9 @@ enum Option {
OPTION_KILL,
OPTION_NO_CONFIG,
OPTION_NO_DAEMON,
#ifdef __linux__
OPTION_SYSTEMD,
#endif
OPTION_STDOUT,
OPTION_STDERR,
OPTION_VERBOSE,
@ -97,6 +101,9 @@ static constexpr OptionDef option_defs[] = {
{"kill", "kill the currently running mpd session"},
{"no-config", "don't read from config"},
{"no-daemon", "don't detach from console"},
#ifdef __linux__
{"systemd", "systemd service mode"},
#endif
{"stdout", nullptr}, // hidden, compatibility with old versions
{"stderr", "print messages to stderr"},
{"verbose", 'v', "verbose logging"},
@ -327,7 +334,7 @@ bool ConfigLoader::TryFile(const AllocatedPath &base_path, Path path)
}
void
ParseCommandLine(int argc, char **argv, struct options &options,
ParseCommandLine(int argc, char **argv, CommandLineOptions &options,
ConfigData &config)
{
bool use_config_file = true;
@ -345,9 +352,20 @@ ParseCommandLine(int argc, char **argv, struct options &options,
break;
case OPTION_NO_DAEMON:
#ifdef ENABLE_DAEMON
options.daemon = false;
#endif
break;
#ifdef __linux__
case OPTION_SYSTEMD:
#ifdef ENABLE_DAEMON
options.daemon = false;
#endif
options.systemd = true;
break;
#endif
case OPTION_STDOUT:
case OPTION_STDERR:
options.log_stderr = true;

@ -20,17 +20,29 @@
#ifndef MPD_COMMAND_LINE_HXX
#define MPD_COMMAND_LINE_HXX
#include "config.h" // for ENABLE_DAEMON
struct ConfigData;
struct options {
struct CommandLineOptions {
bool kill = false;
#ifdef ENABLE_DAEMON
bool daemon = true;
#else
static constexpr bool daemon = false;
#endif
#ifdef __linux__
bool systemd = false;
#endif
bool log_stderr = false;
bool verbose = false;
};
void
ParseCommandLine(int argc, char **argv, struct options &options,
ParseCommandLine(int argc, char **argv, CommandLineOptions &options,
ConfigData &config);
#endif

@ -27,7 +27,7 @@
#include <cassert>
static const char *const idle_names[] = {
static constexpr const char * idle_names[] = {
"database",
"stored_playlist",
"playlist",
@ -42,7 +42,7 @@ static const char *const idle_names[] = {
"neighbor",
"mount",
"partition",
nullptr
nullptr,
};
const char*const*

@ -25,8 +25,6 @@
#ifndef MPD_IDLE_FLAGS_HXX
#define MPD_IDLE_FLAGS_HXX
#include "util/Compiler.h"
/** song database has been updated*/
static constexpr unsigned IDLE_DATABASE = 0x1;
@ -73,7 +71,7 @@ static constexpr unsigned IDLE_PARTITION = 0x2000;
/**
* Get idle names
*/
gcc_const
[[gnu::const]]
const char*const*
idle_get_names() noexcept;
@ -81,7 +79,7 @@ idle_get_names() noexcept;
* Parse an idle name and return its mask. Returns 0 if the given
* name is unknown.
*/
gcc_nonnull_all gcc_pure
[[gnu::nonnull]] [[gnu::pure]]
unsigned
idle_parse_name(const char *name) noexcept;

@ -37,6 +37,10 @@
#include "db/update/Service.hxx"
#include "storage/StorageInterface.hxx"
#ifdef ENABLE_INOTIFY
#include "db/update/InotifyUpdate.hxx"
#endif
#ifdef ENABLE_NEIGHBOR_PLUGINS
#include "neighbor/Glue.hxx"
#endif

@ -24,7 +24,6 @@
#include "event/Loop.hxx"
#include "event/Thread.hxx"
#include "event/MaskMonitor.hxx"
#include "util/Compiler.h"
#ifdef ENABLE_SYSTEMD_DAEMON
#include "lib/systemd/Watchdog.hxx"
@ -44,6 +43,9 @@ class NeighborGlue;
#include "db/Ptr.hxx"
class Storage;
class UpdateService;
#ifdef ENABLE_INOTIFY
class InotifyUpdate;
#endif
#endif
#include <memory>
@ -121,6 +123,10 @@ struct Instance final
Storage *storage = nullptr;
UpdateService *update = nullptr;
#ifdef ENABLE_INOTIFY
std::unique_ptr<InotifyUpdate> inotify_update;
#endif
#endif
#ifdef ENABLE_CURL
@ -168,7 +174,7 @@ struct Instance final
* Find a #Partition with the given name. Returns nullptr if
* no such partition was found.
*/
gcc_pure
[[gnu::pure]]
Partition *FindPartition(const char *name) noexcept;
void DeletePartition(Partition &partition) noexcept;
@ -194,7 +200,7 @@ struct Instance final
#endif
#ifdef ENABLE_SQLITE
bool HasStickerDatabase() noexcept {
bool HasStickerDatabase() const noexcept {
return sticker_database != nullptr;
}
#endif

@ -25,13 +25,17 @@
#include "config/Data.hxx"
#include "config/Option.hxx"
#include "config/Net.hxx"
#include "lib/fmt/ExceptionFormatter.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "net/AllocatedSocketAddress.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "net/SocketUtil.hxx"
#include "system/Error.hxx"
#include "util/RuntimeError.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/StandardDirectory.hxx"
#include "fs/XDG.hxx"
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include <sys/stat.h>
@ -41,6 +45,10 @@
#define DEFAULT_PORT 6600
#if defined(USE_XDG) && defined(HAVE_UN)
static constexpr Domain listen_domain("listen");
#endif
int listen_port;
#ifdef ENABLE_SYSTEMD_DAEMON
@ -78,13 +86,10 @@ ListenXdgRuntimeDir(ClientListener &listener) noexcept
use $XDG_RUNTIME_DIR */
return false;
Path xdg_runtime_dir = Path::FromFS(getenv("XDG_RUNTIME_DIR"));
if (xdg_runtime_dir.IsNull())
const auto mpd_runtime_dir = GetAppRuntimeDir();
if (mpd_runtime_dir.IsNull())
return false;
const auto mpd_runtime_dir = xdg_runtime_dir / Path::FromFS("mpd");
mkdir(mpd_runtime_dir.c_str(), 0700);
const auto socket_path = mpd_runtime_dir / Path::FromFS("socket");
unlink(socket_path.c_str());
@ -98,9 +103,9 @@ ListenXdgRuntimeDir(ClientListener &listener) noexcept
listener.AddFD(std::move(fd), std::move(address));
return true;
} catch (...) {
FormatError(std::current_exception(),
"Failed to listen on '%s' (not fatal)",
socket_path.c_str());
FmtError(listen_domain,
"Failed to listen on '{}' (not fatal): {}",
socket_path, std::current_exception());
return false;
}
#else

@ -22,6 +22,7 @@
#include "client/Client.hxx"
#include "fs/AllocatedPath.hxx"
#include "ls.hxx"
#include "storage/Registry.hxx"
#include "util/ASCII.hxx"
#include "util/UriExtract.hxx"
@ -47,15 +48,14 @@ LocateFileUri(const char *uri, const Client *client
/* this path was relative to the music
directory */
// TODO: don't use suffix.data() (ok for now because we know it's null-terminated)
return LocatedUri(LocatedUri::Type::RELATIVE,
suffix.data());
return {LocatedUri::Type::RELATIVE, suffix.data()};
}
#endif
if (client != nullptr)
client->AllowFile(path);
return LocatedUri(LocatedUri::Type::PATH, uri, std::move(path));
return {LocatedUri::Type::PATH, uri, std::move(path)};
}
static LocatedUri
@ -67,9 +67,13 @@ LocateAbsoluteUri(UriPluginKind kind, const char *uri
{
switch (kind) {
case UriPluginKind::INPUT:
case UriPluginKind::STORAGE: // TODO: separate check for storage plugins
if (!uri_supported_scheme(uri))
throw std::runtime_error("Unsupported URI scheme");
throw std::invalid_argument("Unsupported URI scheme");
break;
case UriPluginKind::STORAGE:
/* plugin support will be checked after the
Storage::MapToRelativeUTF8() call */
break;
case UriPluginKind::PLAYLIST:
@ -85,12 +89,15 @@ LocateAbsoluteUri(UriPluginKind kind, const char *uri
const auto suffix = storage->MapToRelativeUTF8(uri);
if (suffix.data() != nullptr)
// TODO: don't use suffix.data() (ok for now because we know it's null-terminated)
return LocatedUri(LocatedUri::Type::RELATIVE,
suffix.data());
return {LocatedUri::Type::RELATIVE, suffix.data()};
}
if (kind == UriPluginKind::STORAGE &&
GetStoragePluginByUri(uri) == nullptr)
throw std::invalid_argument("Unsupported URI scheme");
#endif
return LocatedUri(LocatedUri::Type::ABSOLUTE, uri);
return {LocatedUri::Type::ABSOLUTE, uri};
}
LocatedUri
@ -105,7 +112,7 @@ LocateUri(UriPluginKind kind,
const char *path_utf8 = StringAfterPrefixCaseASCII(uri, "file://");
if (path_utf8 != nullptr) {
if (!PathTraitsUTF8::IsAbsolute(path_utf8))
throw std::runtime_error("Malformed file:// URI");
throw std::invalid_argument("Malformed file:// URI");
return LocateFileUri(path_utf8, client
#ifdef ENABLE_DATABASE

@ -17,166 +17,35 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "LogV.hxx"
#include "Log.hxx"
#include "lib/fmt/ExceptionFormatter.hxx"
#include "util/Domain.hxx"
#include "util/Exception.hxx"
#include <cerrno>
#include <stdio.h>
#include <string.h>
#include <fmt/format.h>
static constexpr Domain exception_domain("exception");
void
LogFormatV(LogLevel level, const Domain &domain,
const char *fmt, std::va_list ap) noexcept
LogVFmt(LogLevel level, const Domain &domain,
fmt::string_view format_str, fmt::format_args args) noexcept
{
char msg[1024];
vsnprintf(msg, sizeof(msg), fmt, ap);
Log(level, domain, msg);
}
void
LogFormat(LogLevel level, const Domain &domain, const char *fmt, ...) noexcept
{
std::va_list ap;
va_start(ap, fmt);
LogFormatV(level, domain, fmt, ap);
va_end(ap);
}
void
FormatDebug(const Domain &domain, const char *fmt, ...) noexcept
{
std::va_list ap;
va_start(ap, fmt);
LogFormatV(LogLevel::DEBUG, domain, fmt, ap);
va_end(ap);
}
void
FormatInfo(const Domain &domain, const char *fmt, ...) noexcept
{
std::va_list ap;
va_start(ap, fmt);
LogFormatV(LogLevel::INFO, domain, fmt, ap);
va_end(ap);
}
void
FormatNotice(const Domain &domain, const char *fmt, ...) noexcept
{
std::va_list ap;
va_start(ap, fmt);
LogFormatV(LogLevel::NOTICE, domain, fmt, ap);
va_end(ap);
}
void
FormatWarning(const Domain &domain, const char *fmt, ...) noexcept
{
std::va_list ap;
va_start(ap, fmt);
LogFormatV(LogLevel::WARNING, domain, fmt, ap);
va_end(ap);
}
void
FormatError(const Domain &domain, const char *fmt, ...) noexcept
{
std::va_list ap;
va_start(ap, fmt);
LogFormatV(LogLevel::ERROR, domain, fmt, ap);
va_end(ap);
}
void
Log(LogLevel level, const std::exception &e) noexcept
{
Log(level, exception_domain, GetFullMessage(e).c_str());
}
void
Log(LogLevel level, const std::exception &e, const char *msg) noexcept
{
LogFormat(level, exception_domain, "%s: %s", msg, GetFullMessage(e).c_str());
}
void
LogFormat(LogLevel level, const std::exception &e, const char *fmt, ...) noexcept
{
char msg[1024];
std::va_list ap;
va_start(ap, fmt);
vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
Log(level, e, msg);
fmt::memory_buffer buffer;
#if FMT_VERSION >= 80000
fmt::vformat_to(std::back_inserter(buffer), format_str, args);
#else
fmt::vformat_to(buffer, format_str, args);
#endif
Log(level, domain, {buffer.data(), buffer.size()});
}
void
Log(LogLevel level, const std::exception_ptr &ep) noexcept
{
Log(level, exception_domain, GetFullMessage(ep).c_str());
Log(level, exception_domain, GetFullMessage(ep));
}
void
Log(LogLevel level, const std::exception_ptr &ep, const char *msg) noexcept
{
LogFormat(level, exception_domain, "%s: %s", msg,
GetFullMessage(ep).c_str());
}
void
LogFormat(LogLevel level, const std::exception_ptr &ep, const char *fmt, ...) noexcept
{
char msg[1024];
std::va_list ap;
va_start(ap, fmt);
vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
Log(level, ep, msg);
}
void
LogErrno(const Domain &domain, int e, const char *msg) noexcept
{
LogFormat(LogLevel::ERROR, domain, "%s: %s", msg, strerror(e));
}
void
LogErrno(const Domain &domain, const char *msg) noexcept
{
LogErrno(domain, errno, msg);
}
static void
FormatErrnoV(const Domain &domain, int e, const char *fmt, std::va_list ap) noexcept
{
char msg[1024];
vsnprintf(msg, sizeof(msg), fmt, ap);
LogErrno(domain, e, msg);
}
void
FormatErrno(const Domain &domain, int e, const char *fmt, ...) noexcept
{
std::va_list ap;
va_start(ap, fmt);
FormatErrnoV(domain, e, fmt, ap);
va_end(ap);
}
void
FormatErrno(const Domain &domain, const char *fmt, ...) noexcept
{
const int e = errno;
std::va_list ap;
va_start(ap, fmt);
FormatErrnoV(domain, e, fmt, ap);
va_end(ap);
LogFmt(level, exception_domain, "{}: {}", msg, ep);
}

@ -21,29 +21,83 @@
#define MPD_LOG_HXX
#include "LogLevel.hxx"
#include "util/Compiler.h"
#include <fmt/core.h>
#if FMT_VERSION < 70000 || FMT_VERSION >= 80000
#include <fmt/format.h>
#endif
#include <exception>
#include <string_view>
#include <utility>
class Domain;
void
Log(LogLevel level, const Domain &domain, const char *msg) noexcept;
gcc_printf(3,4)
void
LogFormat(LogLevel level, const Domain &domain, const char *fmt, ...) noexcept;
Log(LogLevel level, const Domain &domain, std::string_view msg) noexcept;
void
Log(LogLevel level, const std::exception &e) noexcept;
LogVFmt(LogLevel level, const Domain &domain,
fmt::string_view format_str, fmt::format_args args) noexcept;
template<typename S, typename... Args>
void
Log(LogLevel level, const std::exception &e, const char *msg) noexcept;
LogFmt(LogLevel level, const Domain &domain,
const S &format_str, Args&&... args) noexcept
{
#if FMT_VERSION >= 90000
return LogVFmt(level, domain, format_str,
fmt::make_format_args(args...));
#elif FMT_VERSION >= 70000
return LogVFmt(level, domain, fmt::to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str,
args...));
#else
/* expensive fallback for older libfmt versions */
const auto result = fmt::format(format_str, args...);
return Log(level, domain, result);
#endif
}
gcc_printf(3,4)
template<typename S, typename... Args>
void
LogFormat(LogLevel level, const std::exception &e,
const char *fmt, ...) noexcept;
FmtDebug(const Domain &domain,
const S &format_str, Args&&... args) noexcept
{
LogFmt(LogLevel::DEBUG, domain, format_str, args...);
}
template<typename S, typename... Args>
void
FmtInfo(const Domain &domain,
const S &format_str, Args&&... args) noexcept
{
LogFmt(LogLevel::INFO, domain, format_str, args...);
}
template<typename S, typename... Args>
void
FmtNotice(const Domain &domain,
const S &format_str, Args&&... args) noexcept
{
LogFmt(LogLevel::NOTICE, domain, format_str, args...);
}
template<typename S, typename... Args>
void
FmtWarning(const Domain &domain,
const S &format_str, Args&&... args) noexcept
{
LogFmt(LogLevel::WARNING, domain, format_str, args...);
}
template<typename S, typename... Args>
void
FmtError(const Domain &domain,
const S &format_str, Args&&... args) noexcept
{
LogFmt(LogLevel::ERROR, domain, format_str, args...);
}
void
Log(LogLevel level, const std::exception_ptr &ep) noexcept;
@ -51,76 +105,36 @@ Log(LogLevel level, const std::exception_ptr &ep) noexcept;
void
Log(LogLevel level, const std::exception_ptr &ep, const char *msg) noexcept;
gcc_printf(3,4)
void
LogFormat(LogLevel level, const std::exception_ptr &ep,
const char *fmt, ...) noexcept;
static inline void
LogDebug(const Domain &domain, const char *msg) noexcept
{
Log(LogLevel::DEBUG, domain, msg);
}
gcc_printf(2,3)
void
FormatDebug(const Domain &domain, const char *fmt, ...) noexcept;
static inline void
LogInfo(const Domain &domain, const char *msg) noexcept
{
Log(LogLevel::INFO, domain, msg);
}
gcc_printf(2,3)
void
FormatInfo(const Domain &domain, const char *fmt, ...) noexcept;
static inline void
LogNotice(const Domain &domain, const char *msg) noexcept
{
Log(LogLevel::NOTICE, domain, msg);
}
gcc_printf(2,3)
void
FormatNotice(const Domain &domain, const char *fmt, ...) noexcept;
static inline void
LogWarning(const Domain &domain, const char *msg) noexcept
{
Log(LogLevel::WARNING, domain, msg);
}
gcc_printf(2,3)
void
FormatWarning(const Domain &domain, const char *fmt, ...) noexcept;
static inline void
LogError(const Domain &domain, const char *msg) noexcept
{
Log(LogLevel::ERROR, domain, msg);
}
inline void
LogError(const std::exception &e) noexcept
{
Log(LogLevel::ERROR, e);
}
inline void
LogError(const std::exception &e, const char *msg) noexcept
{
Log(LogLevel::ERROR, e, msg);
}
template<typename... Args>
inline void
FormatError(const std::exception &e, const char *fmt, Args&&... args) noexcept
{
LogFormat(LogLevel::ERROR, e, fmt, std::forward<Args>(args)...);
}
inline void
LogError(const std::exception_ptr &ep) noexcept
{
@ -133,30 +147,4 @@ LogError(const std::exception_ptr &ep, const char *msg) noexcept
Log(LogLevel::ERROR, ep, msg);
}
template<typename... Args>
inline void
FormatError(const std::exception_ptr &ep,
const char *fmt, Args&&... args) noexcept
{
LogFormat(LogLevel::ERROR, ep, fmt, std::forward<Args>(args)...);
}
gcc_printf(2,3)
void
FormatError(const Domain &domain, const char *fmt, ...) noexcept;
void
LogErrno(const Domain &domain, int e, const char *msg) noexcept;
void
LogErrno(const Domain &domain, const char *msg) noexcept;
gcc_printf(3,4)
void
FormatErrno(const Domain &domain, int e, const char *fmt, ...) noexcept;
gcc_printf(2,3)
void
FormatErrno(const Domain &domain, const char *fmt, ...) noexcept;
#endif /* LOG_H */

@ -19,6 +19,7 @@
#include "LogBackend.hxx"
#include "Log.hxx"
#include "util/Compiler.h"
#include "util/Domain.hxx"
#include "util/StringStrip.hxx"
#include "Version.h"
@ -103,15 +104,14 @@ log_date() noexcept
* characters.
*/
static int
chomp_length(const char *p) noexcept
chomp_length(std::string_view p) noexcept
{
size_t length = strlen(p);
return StripRight(p, length);
return StripRight(p.data(), p.size());
}
#ifdef HAVE_SYSLOG
gcc_const
[[gnu::const]]
static int
ToSysLogLevel(LogLevel log_level) noexcept
{
@ -137,11 +137,11 @@ ToSysLogLevel(LogLevel log_level) noexcept
}
static void
SysLog(const Domain &domain, LogLevel log_level, const char *message) noexcept
SysLog(const Domain &domain, LogLevel log_level, std::string_view message) noexcept
{
syslog(ToSysLogLevel(log_level), "%s: %.*s",
domain.GetName(),
chomp_length(message), message);
chomp_length(message), message.data());
}
void
@ -161,12 +161,12 @@ LogFinishSysLog() noexcept
#endif
static void
FileLog(const Domain &domain, const char *message) noexcept
FileLog(const Domain &domain, std::string_view message) noexcept
{
fprintf(stderr, "%s%s: %.*s\n",
enable_timestamp ? log_date() : "",
domain.GetName(),
chomp_length(message), message);
chomp_length(message), message.data());
#ifdef _WIN32
/* force-flush the log file, because setvbuf() does not seem
@ -178,14 +178,20 @@ FileLog(const Domain &domain, const char *message) noexcept
#endif /* !ANDROID */
void
Log(LogLevel level, const Domain &domain, const char *msg) noexcept
Log(LogLevel level, const Domain &domain, std::string_view msg) noexcept
{
#ifdef ANDROID
__android_log_print(ToAndroidLogLevel(level), "MPD",
"%s: %s", domain.GetName(), msg);
if (logListener != nullptr)
"%s: %.*s", domain.GetName(),
(int)msg.size(), msg.data());
if (logListener != nullptr) {
char buffer[1024];
snprintf(buffer, sizeof(buffer), "%s: %.*s",
domain.GetName(), (int)msg.size(), msg.data());
logListener->OnLog(Java::GetEnv(), ToAndroidLogLevel(level),
"%s: %s", domain.GetName(), msg);
buffer);
}
#else
if (level < log_threshold)

@ -158,12 +158,15 @@ log_init(const ConfigData &config, bool verbose, bool use_stdout)
getenv("NOTIFY_SOCKET") != nullptr) {
/* if MPD was started as a systemd
service, default to journal (which
is connected to fd=2) */
is connected to stdout&stderr) */
out_fd = STDOUT_FILENO;
return;
}
#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");
#endif
#ifdef HAVE_SYSLOG
@ -234,22 +237,22 @@ cycle_log_files() noexcept
if (out_path.IsNull())
return 0;
FormatDebug(log_domain, "Cycling log files");
LogDebug(log_domain, "Cycling log files");
close_log_files();
fd = open_log_file();
if (fd < 0) {
const std::string out_path_utf8 = out_path.ToUTF8();
FormatError(log_domain,
"error re-opening log file: %s",
out_path_utf8.c_str());
FmtError(log_domain,
"error re-opening log file: {}",
out_path_utf8);
return -1;
}
redirect_logs(fd);
close(fd);
FormatDebug(log_domain, "Done cycling log files");
LogDebug(log_domain, "Done cycling log files");
return 0;
#endif
}

@ -40,10 +40,11 @@
#include "input/cache/Config.hxx"
#include "input/cache/Manager.hxx"
#include "event/Loop.hxx"
#include "event/Call.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/Config.hxx"
#include "playlist/PlaylistRegistry.hxx"
#include "zeroconf/ZeroconfGlue.hxx"
#include "zeroconf/Glue.hxx"
#include "decoder/DecoderList.hxx"
#include "pcm/AudioParser.hxx"
#include "pcm/Convert.hxx"
@ -141,14 +142,24 @@ struct Config {
#ifdef ENABLE_DAEMON
static void
glue_daemonize_init(const struct options *options,
glue_daemonize_init(const CommandLineOptions &options,
const ConfigData &config)
{
auto pid_file = config.GetPath(ConfigOption::PID_FILE);
#ifdef __linux__
if (options.systemd && pid_file != nullptr) {
pid_file = nullptr;
fprintf(stderr,
"Ignoring the 'pid_file' setting in systemd mode\n");
}
#endif
daemonize_init(config.GetString(ConfigOption::USER),
config.GetString(ConfigOption::GROUP),
config.GetPath(ConfigOption::PID_FILE));
std::move(pid_file));
if (options->kill)
if (options.kill)
daemonize_kill();
}
@ -157,7 +168,17 @@ glue_daemonize_init(const struct options *options,
static void
glue_mapper_init(const ConfigData &config)
{
mapper_init(config.GetPath(ConfigOption::PLAYLIST_DIR));
auto playlist_directory = config.GetPath(ConfigOption::PLAYLIST_DIR);
#ifdef ANDROID
/* if there is no explicit configuration, store playlists in
"/sdcard/Android/data/org.musicpd/files/playlists" */
if (playlist_directory.IsNull())
playlist_directory = context->GetExternalFilesDir(Java::GetEnv(),
"playlists");
#endif
mapper_init(std::move(playlist_directory));
}
#ifdef ENABLE_DATABASE
@ -286,9 +307,8 @@ initialize_decoder_and_player(Instance &instance,
"positive integer", s);
if (result < MIN_BUFFER_SIZE) {
FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
(unsigned long)result,
(unsigned long)MIN_BUFFER_SIZE);
FmtWarning(config_domain, "buffer size {} is too small, using {} bytes instead",
result, MIN_BUFFER_SIZE);
result = MIN_BUFFER_SIZE;
}
@ -334,7 +354,7 @@ Instance::BeginShutdownUpdate() noexcept
{
#ifdef ENABLE_DATABASE
#ifdef ENABLE_INOTIFY
mpd_inotify_finish();
inotify_update.reset();
#endif
if (update != nullptr)
@ -351,7 +371,8 @@ Instance::BeginShutdownPartitions() noexcept
}
static inline void
MainConfigured(const struct options &options, const ConfigData &raw_config)
MainConfigured(const CommandLineOptions &options,
const ConfigData &raw_config)
{
#ifdef ENABLE_DAEMON
daemonize_close_stdin();
@ -374,7 +395,7 @@ MainConfigured(const struct options &options, const ConfigData &raw_config)
const Config config(raw_config);
#ifdef ENABLE_DAEMON
glue_daemonize_init(&options, raw_config);
glue_daemonize_init(options, raw_config);
#endif
TagLoadConfig(raw_config);
@ -441,7 +462,8 @@ MainConfigured(const struct options &options, const ConfigData &raw_config)
command_init();
for (auto &partition : instance.partitions) {
partition.outputs.Configure(instance.rtio_thread.GetEventLoop(),
partition.outputs.Configure(instance.io_thread.GetEventLoop(),
instance.rtio_thread.GetEventLoop(),
raw_config,
config.replay_gain);
partition.UpdateEffectiveReplayGainMode();
@ -460,7 +482,10 @@ MainConfigured(const struct options &options, const ConfigData &raw_config)
#ifndef ANDROID
setup_log_output();
const ScopeSignalHandlersInit signal_handlers_init(instance);
const ScopeSignalHandlersInit signal_handlers_init{
instance,
options.daemon,
};
#endif
instance.io_thread.Start();
@ -476,7 +501,27 @@ MainConfigured(const struct options &options, const ConfigData &raw_config)
};
#endif
ZeroconfInit(raw_config, instance.event_loop);
#ifdef HAVE_ZEROCONF
std::unique_ptr<ZeroconfHelper> zeroconf;
try {
auto &event_loop = instance.io_thread.GetEventLoop();
BlockingCall(event_loop, [&](){
zeroconf = ZeroconfInit(raw_config, event_loop);
});
} catch (...) {
LogError(std::current_exception(),
"Zeroconf initialization failed");
}
AtScopeExit(&zeroconf, &instance) {
if (zeroconf) {
auto &event_loop = instance.io_thread.GetEventLoop();
BlockingCall(event_loop, [&](){
zeroconf.reset();
});
}
};
#endif
#ifdef ENABLE_DATABASE
if (create_db) {
@ -492,15 +537,21 @@ MainConfigured(const struct options &options, const ConfigData &raw_config)
if (raw_config.GetBool(ConfigOption::AUTO_UPDATE, false)) {
#ifdef ENABLE_INOTIFY
if (instance.storage != nullptr &&
instance.update != nullptr)
mpd_inotify_init(instance.event_loop,
*instance.storage,
*instance.update,
raw_config.GetUnsigned(ConfigOption::AUTO_UPDATE_DEPTH,
INT_MAX));
instance.update != nullptr) {
try {
instance.inotify_update =
mpd_inotify_init(instance.event_loop,
*instance.storage,
*instance.update,
raw_config.GetUnsigned(ConfigOption::AUTO_UPDATE_DEPTH,
INT_MAX));
} catch (...) {
LogError(std::current_exception());
}
}
#else
FormatWarning(config_domain,
"inotify: auto_update was disabled. enable during compilation phase");
LogWarning(config_domain,
"inotify: auto_update was disabled. enable during compilation phase");
#endif
}
#endif
@ -537,27 +588,51 @@ MainConfigured(const struct options &options, const ConfigData &raw_config)
instance.state_file->Write();
instance.BeginShutdownUpdate();
ZeroconfDeinit();
instance.BeginShutdownPartitions();
}
#ifdef ANDROID
static void
AndroidMain()
/**
* Wrapper for ReadConfigFile() which returns false if the file was
* not found.
*/
static bool
TryReadConfigFile(ConfigData &config, Path path)
{
struct options options;
if (!FileExists(path))
return false;
ReadConfigFile(config, path);
return true;
}
static void
LoadConfigFile(JNIEnv *env, ConfigData &config)
{
/* try loading mpd.conf from
"Android/data/org.musicpd/files/mpd.conf" (the app specific
data directory) first */
if (const auto dir = context->GetExternalFilesDir(env);
!dir.IsNull() &&
TryReadConfigFile(config, dir / Path::FromFS("mpd.conf")))
return;
/* if that fails, attempt to load "mpd.conf" from the root of
the SD card (pre-0.23.9, ceases to work since Android
12) */
if (const auto dir = Environment::getExternalStorageDirectory(env);
!dir.IsNull())
TryReadConfigFile(config, dir / Path::FromFS("mpd.conf"));
}
static void
AndroidMain(JNIEnv *env)
{
CommandLineOptions options;
ConfigData raw_config;
const auto sdcard = Environment::getExternalStorageDirectory();
if (!sdcard.IsNull()) {
const auto config_path =
sdcard / Path::FromFS("mpd.conf");
if (FileExists(config_path))
ReadConfigFile(raw_config, config_path);
}
LoadConfigFile(env, raw_config);
MainConfigured(options, raw_config);
}
@ -569,9 +644,12 @@ Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context, jobject _logL
Java::Init(env);
Java::Object::Initialise(env);
Java::File::Initialise(env);
Environment::Initialise(env);
AtScopeExit(env) { Environment::Deinitialise(env); };
Context::Initialise(env);
context = new Context(env, _context);
AtScopeExit() { delete context; };
@ -580,7 +658,7 @@ Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context, jobject _logL
AtScopeExit() { delete logListener; };
try {
AndroidMain();
AndroidMain(env);
} catch (...) {
LogError(std::current_exception());
}
@ -594,12 +672,21 @@ Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
global_instance->Break();
}
gcc_visibility_default
JNIEXPORT void JNICALL
Java_org_musicpd_Bridge_pause(JNIEnv *, jclass)
{
if (global_instance != nullptr)
for (auto &partition : global_instance->partitions)
partition.pc.LockSetPause(true);
}
#else
static inline void
MainOrThrow(int argc, char *argv[])
{
struct options options;
CommandLineOptions options;
ConfigData raw_config;
ParseCommandLine(argc, argv, options, raw_config);
@ -607,27 +694,26 @@ MainOrThrow(int argc, char *argv[])
MainConfigured(options, raw_config);
}
int mpd_main(int argc, char *argv[]) noexcept
int
mpd_main(int argc, char *argv[])
{
AtScopeExit() { log_deinit(); };
try {
MainOrThrow(argc, argv);
return EXIT_SUCCESS;
} catch (...) {
LogError(std::current_exception());
return EXIT_FAILURE;
}
MainOrThrow(argc, argv);
return EXIT_SUCCESS;
}
int
main(int argc, char *argv[]) noexcept
{
try {
AtScopeExit() { log_deinit(); };
#ifdef _WIN32
return win32_main(argc, argv);
#else
return mpd_main(argc, argv);
#endif
} catch (...) {
LogError(std::current_exception());
return EXIT_FAILURE;
}
#endif

@ -40,7 +40,7 @@ extern Instance *global_instance;
* after doing some initialization.
*/
int
mpd_main(int argc, char *argv[]) noexcept;
mpd_main(int argc, char *argv[]);
#endif

@ -85,15 +85,15 @@ map_fs_to_utf8(Path path_fs) noexcept
{
if (path_fs.IsAbsolute()) {
if (global_instance->storage == nullptr)
return std::string();
return {};
const auto music_dir_fs = global_instance->storage->MapFS("");
if (music_dir_fs.IsNull())
return std::string();
return {};
auto relative = music_dir_fs.Relative(path_fs);
if (relative == nullptr || StringIsEmpty(relative))
return std::string();
return {};
path_fs = Path::FromFS(relative);
}

@ -24,7 +24,6 @@
#ifndef MPD_MAPPER_HXX
#define MPD_MAPPER_HXX
#include "util/Compiler.h"
#include "config.h"
#include <string>
@ -44,7 +43,7 @@ mapper_init(AllocatedPath &&playlist_dir);
* is basically done by converting the URI to the file system charset
* and prepending the music directory.
*/
gcc_pure
[[gnu::pure]]
AllocatedPath
map_uri_fs(const char *uri) noexcept;
@ -56,7 +55,7 @@ map_uri_fs(const char *uri) noexcept;
* @return the relative path in UTF-8, or an empty string if mapping
* failed
*/
gcc_pure
[[gnu::pure]]
std::string
map_fs_to_utf8(Path path_fs) noexcept;
@ -65,7 +64,7 @@ map_fs_to_utf8(Path path_fs) noexcept;
/**
* Returns the playlist directory.
*/
gcc_const
[[gnu::const]]
const AllocatedPath &
map_spl_path() noexcept;
@ -75,7 +74,7 @@ map_spl_path() noexcept;
*
* @return the path in file system encoding, or nullptr if mapping failed
*/
gcc_pure
[[gnu::pure]]
AllocatedPath
map_spl_utf8_to_fs(const char *name) noexcept;

@ -29,8 +29,8 @@ MusicBuffer::MusicBuffer(unsigned num_chunks)
MusicChunkPtr
MusicBuffer::Allocate() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
return MusicChunkPtr(buffer.Allocate(), MusicChunkDeleter(*this));
const std::scoped_lock<Mutex> protect(mutex);
return {buffer.Allocate(), MusicChunkDeleter(*this)};
}
void
@ -44,7 +44,7 @@ MusicBuffer::Return(MusicChunk *chunk) noexcept
chunk->next.reset();
chunk->other.reset();
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(!chunk->other || !chunk->other->other);

@ -54,7 +54,7 @@ public:
#endif
bool IsFull() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return buffer.IsFull();
}
@ -63,7 +63,7 @@ public:
* is the same value which was passed to the constructor
* music_buffer_new().
*/
gcc_pure
[[gnu::pure]]
unsigned GetSize() const noexcept {
return buffer.GetCapacity();
}

@ -105,7 +105,7 @@ struct MusicChunkInfo {
* Checks if the audio format if the chunk is equal to the
* specified audio_format.
*/
gcc_pure
[[gnu::pure]]
bool CheckFormat(AudioFormat audio_format) const noexcept;
#endif
};

@ -27,7 +27,7 @@
bool
MusicPipe::Contains(const MusicChunk *chunk) const noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
for (const MusicChunk *i = head.get(); i != nullptr; i = i->next.get())
if (i == chunk)
@ -41,7 +41,7 @@ MusicPipe::Contains(const MusicChunk *chunk) const noexcept
MusicChunkPtr
MusicPipe::Shift() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
auto chunk = std::move(head);
if (chunk != nullptr) {
@ -81,7 +81,7 @@ MusicPipe::Push(MusicChunkPtr chunk) noexcept
assert(!chunk->IsEmpty());
assert(chunk->length == 0 || chunk->audio_format.IsValid());
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(size > 0 || !audio_format.IsDefined());
assert(!audio_format.IsDefined() ||

@ -22,7 +22,6 @@
#include "MusicChunkPtr.hxx"
#include "thread/Mutex.hxx"
#include "util/Compiler.h"
#ifndef NDEBUG
#include "pcm/AudioFormat.hxx"
@ -59,7 +58,7 @@ public:
* Checks if the audio format if the chunk is equal to the specified
* audio_format.
*/
gcc_pure
[[gnu::pure]]
bool CheckFormat(AudioFormat other) const noexcept {
return !audio_format.IsDefined() ||
audio_format == other;
@ -68,7 +67,7 @@ public:
/**
* Checks if the specified chunk is enqueued in the music pipe.
*/
gcc_pure
[[gnu::pure]]
bool Contains(const MusicChunk *chunk) const noexcept;
#endif
@ -76,9 +75,9 @@ public:
* Returns the first #MusicChunk from the pipe. Returns
* nullptr if the pipe is empty.
*/
gcc_pure
[[gnu::pure]]
const MusicChunk *Peek() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return head.get();
}
@ -100,13 +99,13 @@ public:
/**
* Returns the number of chunks currently in this pipe.
*/
gcc_pure
[[gnu::pure]]
unsigned GetSize() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return size;
}
gcc_pure
[[gnu::pure]]
bool IsEmpty() const noexcept {
return GetSize() == 0;
}

@ -21,8 +21,8 @@
#include "Partition.hxx"
#include "Instance.hxx"
#include "Log.hxx"
#include "lib/fmt/ExceptionFormatter.hxx"
#include "song/DetachedSong.hxx"
#include "mixer/Volume.hxx"
#include "IdleFlags.hxx"
#include "client/Listener.hxx"
#include "client/Client.hxx"
@ -67,13 +67,14 @@ PrefetchSong(InputCacheManager &cache, const char *uri) noexcept
if (cache.Contains(uri))
return;
FormatDebug(cache_domain, "Prefetch '%s'", uri);
FmtDebug(cache_domain, "Prefetch '{}'", uri);
try {
cache.Prefetch(uri);
} catch (...) {
FormatError(std::current_exception(),
"Prefetch '%s' failed", uri);
FmtError(cache_domain,
"Prefetch '{}' failed: {}",
uri, std::current_exception());
}
}
@ -204,7 +205,7 @@ Partition::OnBorderPause() noexcept
void
Partition::OnMixerVolumeChanged(Mixer &, int) noexcept
{
InvalidateHardwareVolume();
mixer_memento.InvalidateHardwareVolume();
/* notify clients */
EmitIdle(IDLE_MIXER);

@ -25,8 +25,10 @@
#include "queue/Listener.hxx"
#include "output/MultipleOutputs.hxx"
#include "mixer/Listener.hxx"
#include "mixer/Memento.hxx"
#include "player/Control.hxx"
#include "player/Listener.hxx"
#include "protocol/RangeArg.hxx"
#include "ReplayGainMode.hxx"
#include "SingleMode.hxx"
#include "Chrono.hxx"
@ -38,6 +40,7 @@
#include <memory>
struct Instance;
struct RangeArg;
class MultipleOutputs;
class SongLoader;
class ClientListener;
@ -74,6 +77,8 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
MultipleOutputs outputs;
MixerMemento mixer_memento;
PlayerControl pc;
ReplayGainMode replay_gain_mode = ReplayGainMode::OFF;
@ -133,24 +138,20 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
* @param start the position of the first song to delete
* @param end the position after the last song to delete
*/
void DeleteRange(unsigned start, unsigned end) {
playlist.DeleteRange(pc, start, end);
void DeleteRange(RangeArg range) {
playlist.DeleteRange(pc, range);
}
void StaleSong(const char *uri) noexcept {
playlist.StaleSong(pc, uri);
}
void Shuffle(unsigned start, unsigned end) noexcept {
playlist.Shuffle(pc, start, end);
void Shuffle(RangeArg range) {
playlist.Shuffle(pc, range);
}
void MoveRange(unsigned start, unsigned end, int to) {
playlist.MoveRange(pc, start, end, to);
}
void MoveId(unsigned id, int to) {
playlist.MoveId(pc, id, to);
void MoveRange(RangeArg range, unsigned to) {
playlist.MoveRange(pc, range, to);
}
void SwapPositions(unsigned song1, unsigned song2) {
@ -161,10 +162,8 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
playlist.SwapIds(pc, id1, id2);
}
void SetPriorityRange(unsigned start_position, unsigned end_position,
uint8_t priority) {
playlist.SetPriorityRange(pc, start_position, end_position,
priority);
void SetPriorityRange(RangeArg position_range, uint8_t priority) {
playlist.SetPriorityRange(pc, position_range, priority);
}
void SetPriorityId(unsigned song_id, uint8_t priority) {

@ -22,12 +22,14 @@
#include "config/Param.hxx"
#include "config/Data.hxx"
#include "config/Option.hxx"
#include "net/AddressInfo.hxx"
#include "net/Resolver.hxx"
#include "net/ToString.hxx"
#include "util/IterableSplitString.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringView.hxx"
#include <cassert>
#include <cstring>
#include <map>
#include <string>
#include <utility>
@ -41,6 +43,7 @@ static constexpr struct {
} permission_names[] = {
{ "read", PERMISSION_READ },
{ "add", PERMISSION_ADD },
{ "player", PERMISSION_PLAYER },
{ "control", PERMISSION_CONTROL },
{ "admin", PERMISSION_ADMIN },
{ nullptr, 0 },
@ -54,6 +57,10 @@ static unsigned permission_default;
static unsigned local_permissions;
#endif
#ifdef HAVE_TCP
static std::map<std::string, unsigned> host_passwords;
#endif
static unsigned
ParsePermission(StringView s)
{
@ -65,16 +72,20 @@ ParsePermission(StringView s)
int(s.size), s.data);
}
static unsigned parsePermissions(const char *string)
static unsigned
parsePermissions(std::string_view string)
{
assert(string != nullptr);
unsigned permission = 0;
for (const auto i : IterableSplitString(string, PERMISSION_SEPARATOR))
if (!i.empty())
permission |= ParsePermission(i);
/* for backwards compatiblity with MPD 0.22 and older,
"control" implies "play" */
if (permission & PERMISSION_CONTROL)
permission |= PERMISSION_PLAYER;
return permission;
}
@ -82,24 +93,21 @@ void
initPermissions(const ConfigData &config)
{
permission_default = PERMISSION_READ | PERMISSION_ADD |
PERMISSION_PLAYER |
PERMISSION_CONTROL | PERMISSION_ADMIN;
for (const auto &param : config.GetParamList(ConfigOption::PASSWORD)) {
permission_default = 0;
param.With([](const char *value){
const char *separator = std::strchr(value,
PERMISSION_PASSWORD_CHAR);
if (separator == nullptr)
param.With([](const StringView value){
const auto [password, permissions] =
value.Split(PERMISSION_PASSWORD_CHAR);
if (permissions == nullptr)
throw FormatRuntimeError("\"%c\" not found in password string",
PERMISSION_PASSWORD_CHAR);
std::string password(value, separator);
unsigned permission = parsePermissions(separator + 1);
permission_passwords.insert(std::make_pair(std::move(password),
permission));
permission_passwords.emplace(password,
parsePermissions(permissions));
});
}
@ -115,17 +123,48 @@ initPermissions(const ConfigData &config)
: permission_default;
});
#endif
#ifdef HAVE_TCP
for (const auto &param : config.GetParamList(ConfigOption::HOST_PERMISSIONS)) {
permission_default = 0;
param.With([](StringView value){
auto [host_sv, permissions_s] = value.Split(' ');
unsigned permissions = parsePermissions(permissions_s);
const std::string host_s{host_sv};
for (const auto &i : Resolve(host_s.c_str(), 0,
AI_PASSIVE, SOCK_STREAM))
host_passwords.emplace(HostToString(i),
permissions);
});
}
#endif
}
#ifdef HAVE_TCP
int
getPermissionFromPassword(const char *password, unsigned *permission) noexcept
GetPermissionsFromAddress(SocketAddress address) noexcept
{
if (auto i = host_passwords.find(HostToString(address));
i != host_passwords.end())
return i->second;
return -1;
}
#endif
std::optional<unsigned>
GetPermissionFromPassword(const char *password) noexcept
{
auto i = permission_passwords.find(password);
if (i == permission_passwords.end())
return -1;
return std::nullopt;
*permission = i->second;
return 0;
return i->second;
}
unsigned

@ -22,25 +22,42 @@
#include "config.h"
#include <optional>
struct ConfigData;
class SocketAddress;
static constexpr unsigned PERMISSION_NONE = 0;
static constexpr unsigned PERMISSION_READ = 1;
static constexpr unsigned PERMISSION_ADD = 2;
static constexpr unsigned PERMISSION_CONTROL = 4;
static constexpr unsigned PERMISSION_ADMIN = 8;
static constexpr unsigned PERMISSION_PLAYER = 16;
int
getPermissionFromPassword(const char *password, unsigned *permission) noexcept;
/**
* @return the permissions for the given password or std::nullopt if
* the password is not accepted
*/
[[gnu::pure]]
std::optional<unsigned>
GetPermissionFromPassword(const char *password) noexcept;
[[gnu::const]]
unsigned
getDefaultPermissions() noexcept;
#ifdef HAVE_UN
[[gnu::const]]
unsigned
GetLocalPermissions() noexcept;
#endif
#ifdef HAVE_TCP
[[gnu::pure]]
int
GetPermissionsFromAddress(SocketAddress address) noexcept;
#endif
void
initPermissions(const ConfigData &config);

@ -19,8 +19,8 @@
#include "PlaylistDatabase.hxx"
#include "db/PlaylistVector.hxx"
#include "fs/io/TextFile.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "io/LineReader.hxx"
#include "io/BufferedOutputStream.hxx"
#include "time/ChronoUtil.hxx"
#include "util/StringStrip.hxx"
#include "util/RuntimeError.hxx"
@ -42,7 +42,7 @@ playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv)
}
void
playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name)
playlist_metadata_load(LineReader &file, PlaylistVector &pv, const char *name)
{
PlaylistInfo pm(name);

@ -24,7 +24,7 @@
class PlaylistVector;
class BufferedOutputStream;
class TextFile;
class LineReader;
void
playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv);
@ -33,6 +33,7 @@ playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv);
* Throws #std::runtime_error on error.
*/
void
playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name);
playlist_metadata_load(LineReader &file, PlaylistVector &pv,
const char *name);
#endif

@ -26,15 +26,15 @@
#include "song/DetachedSong.hxx"
#include "SongLoader.hxx"
#include "Mapper.hxx"
#include "protocol/RangeArg.hxx"
#include "fs/io/TextFile.hxx"
#include "fs/io/FileOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "io/FileOutputStream.hxx"
#include "io/BufferedOutputStream.hxx"
#include "config/Data.hxx"
#include "config/Option.hxx"
#include "config/Defaults.hxx"
#include "Idle.hxx"
#include "fs/Limits.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/Traits.hxx"
#include "fs/FileSystem.hxx"
#include "fs/FileInfo.hxx"
@ -81,6 +81,9 @@ spl_valid_name(const char *name_utf8)
*/
return std::strchr(name_utf8, '/') == nullptr &&
#ifdef _WIN32
std::strchr(name_utf8, '\\') == nullptr &&
#endif
std::strchr(name_utf8, '\n') == nullptr &&
std::strchr(name_utf8, '\r') == nullptr;
}
@ -173,11 +176,8 @@ ListPlaylistFiles()
}
static void
SavePlaylistFile(const PlaylistFileContents &contents, const char *utf8path)
SavePlaylistFile(Path path_fs, const PlaylistFileContents &contents)
{
assert(utf8path != nullptr);
const auto path_fs = spl_map_to_fs(utf8path);
assert(!path_fs.IsNull());
FileOutputStream fos(path_fs);
@ -191,12 +191,11 @@ SavePlaylistFile(const PlaylistFileContents &contents, const char *utf8path)
fos.Commit();
}
PlaylistFileContents
LoadPlaylistFile(const char *utf8path)
static PlaylistFileContents
LoadPlaylistFile(Path path_fs)
try {
PlaylistFileContents contents;
const auto path_fs = spl_map_to_fs(utf8path);
assert(!path_fs.IsNull());
TextFile file(path_fs);
@ -251,16 +250,54 @@ try {
throw;
}
void
spl_move_index(const char *utf8path, unsigned src, unsigned dest)
static PlaylistFileContents
MaybeLoadPlaylistFile(Path path_fs, PlaylistFileEditor::LoadMode load_mode)
try {
if (load_mode == PlaylistFileEditor::LoadMode::NO)
return {};
return LoadPlaylistFile(path_fs);
} catch (const PlaylistError &error) {
if (error.GetCode() == PlaylistResult::NO_SUCH_LIST &&
load_mode == PlaylistFileEditor::LoadMode::TRY)
return {};
throw;
}
PlaylistFileEditor::PlaylistFileEditor(const char *name_utf8,
LoadMode load_mode)
:path(spl_map_to_fs(name_utf8)),
contents(MaybeLoadPlaylistFile(path, load_mode))
{
if (src == dest)
/* this doesn't check whether the playlist exists, but
what the hell.. */
return;
}
auto contents = LoadPlaylistFile(utf8path);
void
PlaylistFileEditor::Insert(std::size_t i, const char *uri)
{
if (i > size())
throw PlaylistError(PlaylistResult::BAD_RANGE, "Bad position");
if (size() >= playlist_max_length)
throw PlaylistError(PlaylistResult::TOO_LARGE,
"Stored playlist is too large");
contents.emplace(std::next(contents.begin(), i), uri);
}
void
PlaylistFileEditor::Insert(std::size_t i, const DetachedSong &song)
{
const char *uri = playlist_saveAbsolutePaths
? song.GetRealURI()
: song.GetURI();
Insert(i, uri);
}
void
PlaylistFileEditor::MoveIndex(unsigned src, unsigned dest)
{
if (src >= contents.size() || dest >= contents.size())
throw PlaylistError(PlaylistResult::BAD_RANGE, "Bad range");
@ -270,9 +307,31 @@ spl_move_index(const char *utf8path, unsigned src, unsigned dest)
const auto dest_i = std::next(contents.begin(), dest);
contents.insert(dest_i, std::move(value));
}
SavePlaylistFile(contents, utf8path);
void
PlaylistFileEditor::RemoveIndex(unsigned i)
{
if (i >= contents.size())
throw PlaylistError(PlaylistResult::BAD_RANGE, "Bad range");
contents.erase(std::next(contents.begin(), i));
}
void
PlaylistFileEditor::RemoveRange(RangeArg range)
{
if (!range.CheckClip(size()))
throw PlaylistError::BadRange();
contents.erase(std::next(contents.begin(), range.start),
std::next(contents.begin(), range.end));
}
void
PlaylistFileEditor::Save()
{
SavePlaylistFile(path, contents);
idle_add(IDLE_STORED_PLAYLIST);
}
@ -314,20 +373,6 @@ spl_delete(const char *name_utf8)
idle_add(IDLE_STORED_PLAYLIST);
}
void
spl_remove_index(const char *utf8path, unsigned pos)
{
auto contents = LoadPlaylistFile(utf8path);
if (pos >= contents.size())
throw PlaylistError(PlaylistResult::BAD_RANGE, "Bad range");
contents.erase(std::next(contents.begin(), pos));
SavePlaylistFile(contents, utf8path);
idle_add(IDLE_STORED_PLAYLIST);
}
void
spl_append_song(const char *utf8path, const DetachedSong &song)
try {

@ -20,19 +20,55 @@
#ifndef MPD_PLAYLIST_FILE_HXX
#define MPD_PLAYLIST_FILE_HXX
#include "fs/AllocatedPath.hxx"
#include <vector>
#include <string>
struct ConfigData;
struct RangeArg;
class DetachedSong;
class SongLoader;
class PlaylistVector;
class AllocatedPath;
typedef std::vector<std::string> PlaylistFileContents;
extern bool playlist_saveAbsolutePaths;
class PlaylistFileEditor {
const AllocatedPath path;
PlaylistFileContents contents;
public:
enum class LoadMode {
NO,
YES,
TRY,
};
/**
* Throws on error.
*/
explicit PlaylistFileEditor(const char *name_utf8, LoadMode load_mode);
auto size() const noexcept {
return contents.size();
}
void Insert(std::size_t i, const char *uri);
void Insert(std::size_t i, const DetachedSong &song);
void MoveIndex(unsigned src, unsigned dest);
void RemoveIndex(unsigned i);
void RemoveRange(RangeArg range);
void Save();
private:
void Load();
};
/**
* Perform some global initialization, e.g. load configuration values.
*/
@ -55,21 +91,12 @@ spl_map_to_fs(const char *name_utf8);
PlaylistVector
ListPlaylistFiles();
PlaylistFileContents
LoadPlaylistFile(const char *utf8path);
void
spl_move_index(const char *utf8path, unsigned src, unsigned dest);
void
spl_clear(const char *utf8path);
void
spl_delete(const char *name_utf8);
void
spl_remove_index(const char *utf8path, unsigned pos);
void
spl_append_song(const char *utf8path, const DetachedSong &song);

@ -22,6 +22,7 @@
#include "PlaylistError.hxx"
#include "queue/Playlist.hxx"
#include "queue/QueuePrint.hxx"
#include "protocol/RangeArg.hxx"
#define SONG_FILE "file: "
#define SONG_TIME "Time: "
@ -35,20 +36,17 @@ playlist_print_uris(Response &r, const playlist &playlist)
}
void
playlist_print_info(Response &r, const playlist &playlist,
unsigned start, unsigned end)
playlist_print_info(Response &r, const playlist &playlist, RangeArg range)
{
const Queue &queue = playlist.queue;
if (end > queue.GetLength())
/* correct the "end" offset */
end = queue.GetLength();
if (start > end)
/* an invalid "start" offset is fatal */
if (!range.CheckClip(queue.GetLength()))
throw PlaylistError::BadRange();
queue_print_info(r, queue, start, end);
if (range.IsEmpty())
return;
queue_print_info(r, queue, range.start, range.end);
}
void
@ -62,7 +60,7 @@ playlist_print_id(Response &r, const playlist &playlist,
/* no such song */
throw PlaylistError::NoSuchSong();
playlist_print_info(r, playlist, position, position + 1);
playlist_print_info(r, playlist, {unsigned(position), position + 1U});
}
bool
@ -87,18 +85,24 @@ playlist_print_find(Response &r, const playlist &playlist,
void
playlist_print_changes_info(Response &r, const playlist &playlist,
uint32_t version,
unsigned start, unsigned end)
RangeArg range)
{
queue_print_changes_info(r, playlist.queue, version,
start, end);
const Queue &queue = playlist.queue;
range.ClipRelaxed(queue.GetLength());
queue_print_changes_info(r, queue, version,
range.start, range.end);
}
void
playlist_print_changes_position(Response &r,
const playlist &playlist,
uint32_t version,
unsigned start, unsigned end)
RangeArg range)
{
const Queue &queue = playlist.queue;
range.ClipRelaxed(queue.GetLength());
queue_print_changes_position(r, playlist.queue, version,
start, end);
range.start, range.end);
}

@ -23,6 +23,7 @@
#include <cstdint>
struct playlist;
struct RangeArg;
class SongFilter;
class Response;
@ -41,8 +42,7 @@ playlist_print_uris(Response &r, const playlist &playlist);
* Throws #PlaylistError if the range is invalid.
*/
void
playlist_print_info(Response &r, const playlist &playlist,
unsigned start, unsigned end);
playlist_print_info(Response &r, const playlist &playlist, RangeArg range);
/**
* Sends the song with the specified id to the client.
@ -73,7 +73,7 @@ playlist_print_find(Response &r, const playlist &playlist,
void
playlist_print_changes_info(Response &r, const playlist &playlist,
uint32_t version,
unsigned start, unsigned end);
RangeArg range);
/**
* Print changes since the specified playlist version, position only.
@ -82,6 +82,6 @@ void
playlist_print_changes_position(Response &r,
const playlist &playlist,
uint32_t version,
unsigned start, unsigned end);
RangeArg range);
#endif

@ -28,8 +28,8 @@
#include "fs/AllocatedPath.hxx"
#include "fs/Traits.hxx"
#include "fs/FileSystem.hxx"
#include "fs/io/FileOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "io/FileOutputStream.hxx"
#include "io/BufferedOutputStream.hxx"
#include "util/UriExtract.hxx"
static void

@ -19,10 +19,14 @@
#include "RemoteTagCache.hxx"
#include "RemoteTagCacheHandler.hxx"
#include "lib/fmt/ExceptionFormatter.hxx"
#include "input/ScanTags.hxx"
#include "util/DeleteDisposer.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
static constexpr Domain remote_tag_cache_domain("remote_tag_cache");
RemoteTagCache::RemoteTagCache(EventLoop &event_loop,
RemoteTagCacheHandler &_handler) noexcept
:handler(_handler),
@ -60,9 +64,9 @@ RemoteTagCache::Lookup(const std::string &uri) noexcept
item->scanner->Start();
} catch (...) {
FormatError(std::current_exception(),
"Failed to scan tags of '%s'",
uri.c_str());
FmtError(remote_tag_cache_domain,
"Failed to scan tags of '{}': {}",
uri, std::current_exception());
item->scanner.reset();
@ -94,7 +98,7 @@ RemoteTagCache::ItemResolved(Item &item) noexcept
void
RemoteTagCache::InvokeHandlers() noexcept
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
while (!invoke_list.empty()) {
auto &item = invoke_list.front();
@ -121,17 +125,18 @@ RemoteTagCache::Item::OnRemoteTag(Tag &&_tag) noexcept
scanner.reset();
const std::lock_guard<Mutex> lock(parent.mutex);
const std::scoped_lock<Mutex> lock(parent.mutex);
parent.ItemResolved(*this);
}
void
RemoteTagCache::Item::OnRemoteTagError(std::exception_ptr e) noexcept
{
FormatError(e, "Failed to scan tags of '%s'", uri.c_str());
FmtError(remote_tag_cache_domain,
"Failed to scan tags of '{}': {}", uri, e);
scanner.reset();
const std::lock_guard<Mutex> lock(parent.mutex);
const std::scoped_lock<Mutex> lock(parent.mutex);
parent.ItemResolved(*this);
}

@ -22,13 +22,17 @@
#include "input/RemoteTagScanner.hxx"
#include "tag/Tag.hxx"
#include "event/DeferEvent.hxx"
#include "event/InjectEvent.hxx"
#include "thread/Mutex.hxx"
#include <boost/intrusive/list.hpp>
#include <boost/intrusive/unordered_set.hpp>
#include <array>
#include <functional>
#include <memory>
#include <string>
#include <utility>
class RemoteTagCacheHandler;
@ -40,7 +44,7 @@ class RemoteTagCache final {
RemoteTagCacheHandler &handler;
DeferEvent defer_invoke_handler;
InjectEvent defer_invoke_handler;
Mutex mutex;
@ -68,20 +72,20 @@ class RemoteTagCache final {
struct Hash : std::hash<std::string> {
using std::hash<std::string>::operator();
gcc_pure
[[gnu::pure]]
std::size_t operator()(const Item &item) const noexcept {
return std::hash<std::string>::operator()(item.uri);
}
};
struct Equal {
gcc_pure
[[gnu::pure]]
bool operator()(const Item &a,
const Item &b) const noexcept {
return a.uri == b.uri;
}
gcc_pure
[[gnu::pure]]
bool operator()(const std::string &a,
const Item &b) const noexcept {
return a == b.uri;

@ -20,7 +20,6 @@
#ifndef MPD_REPLAY_GAIN_INFO_HXX
#define MPD_REPLAY_GAIN_INFO_HXX
#include "util/Compiler.h"
#include "ReplayGainMode.hxx"
struct ReplayGainConfig;
@ -42,7 +41,7 @@ struct ReplayGainTuple {
return {-200.0f, 0.0f};
}
gcc_pure
[[gnu::pure]]
float CalculateScale(const ReplayGainConfig &config) const noexcept;
};

@ -18,6 +18,7 @@
*/
#include "ReplayGainMode.hxx"
#include "util/Compiler.h"
#include <cassert>
#include <stdexcept>

@ -20,8 +20,6 @@
#ifndef MPD_REPLAY_GAIN_MODE_HXX
#define MPD_REPLAY_GAIN_MODE_HXX
#include "util/Compiler.h"
#include <cstdint>
enum class ReplayGainMode : uint8_t {
@ -34,7 +32,7 @@ enum class ReplayGainMode : uint8_t {
/**
* Return the string representation of a #ReplayGainMode.
*/
gcc_pure
[[gnu::pure]]
const char *
ToString(ReplayGainMode mode) noexcept;

@ -18,6 +18,7 @@
*/
#include "SingleMode.hxx"
#include "util/Compiler.h"
#include <cassert>
#include <stdexcept>

@ -20,8 +20,6 @@
#ifndef MPD_SINGLE_MODE_HXX
#define MPD_SINGLE_MODE_HXX
#include "util/Compiler.h"
#include <cstdint>
enum class SingleMode : uint8_t {
@ -33,7 +31,7 @@ enum class SingleMode : uint8_t {
/**
* Return the string representation of a #SingleMode.
*/
gcc_pure
[[gnu::const]]
const char *
SingleToString(SingleMode mode) noexcept;

@ -20,7 +20,6 @@
#ifndef MPD_SONG_LOADER_HXX
#define MPD_SONG_LOADER_HXX
#include "util/Compiler.h"
#include "config.h"
#include <cstddef>
@ -72,14 +71,14 @@ public:
/**
* Throws #std::runtime_error on error.
*/
gcc_nonnull_all
[[gnu::nonnull]]
DetachedSong LoadSong(const char *uri_utf8) const;
private:
gcc_nonnull_all
[[gnu::nonnull]]
DetachedSong LoadFromDatabase(const char *uri) const;
gcc_nonnull_all
[[gnu::nonnull]]
DetachedSong LoadFile(const char *path_utf8, Path path_fs) const;
};

@ -24,9 +24,13 @@
#include "TagPrint.hxx"
#include "client/Response.hxx"
#include "fs/Traits.hxx"
#include "lib/fmt/AudioFormatFormatter.hxx"
#include "time/ChronoUtil.hxx"
#include "util/StringBuffer.hxx"
#include "util/UriUtil.hxx"
#include <fmt/format.h>
#define SONG_FILE "file: "
static void
@ -42,14 +46,15 @@ song_print_uri(Response &r, const char *uri, bool base) noexcept
uri = allocated.c_str();
}
r.Format(SONG_FILE "%s\n", uri);
r.Fmt(FMT_STRING(SONG_FILE "{}\n"), uri);
}
void
song_print_uri(Response &r, const LightSong &song, bool base) noexcept
{
if (!base && song.directory != nullptr)
r.Format(SONG_FILE "%s/%s\n", song.directory, song.uri);
r.Fmt(FMT_STRING(SONG_FILE "{}/{}\n"),
song.directory, song.uri);
else
song_print_uri(r, song.uri, base);
}
@ -67,15 +72,15 @@ PrintRange(Response &r, SongTime start_time, SongTime end_time) noexcept
const unsigned end_ms = end_time.ToMS();
if (end_ms > 0)
r.Format("Range: %u.%03u-%u.%03u\n",
start_ms / 1000,
start_ms % 1000,
end_ms / 1000,
end_ms % 1000);
r.Fmt(FMT_STRING("Range: {}.{:03}-{}.{:03}\n"),
start_ms / 1000,
start_ms % 1000,
end_ms / 1000,
end_ms % 1000);
else if (start_ms > 0)
r.Format("Range: %u.%03u-\n",
start_ms / 1000,
start_ms % 1000);
r.Fmt(FMT_STRING("Range: {}.{:03}-\n"),
start_ms / 1000,
start_ms % 1000);
}
void
@ -89,16 +94,16 @@ song_print_info(Response &r, const LightSong &song, bool base) noexcept
time_print(r, "Last-Modified", song.mtime);
if (song.audio_format.IsDefined())
r.Format("Format: %s\n", ToString(song.audio_format).c_str());
r.Fmt(FMT_STRING("Format: {}\n"), song.audio_format);
tag_print_values(r, song.tag);
const auto duration = song.GetDuration();
if (!duration.IsNegative())
r.Format("Time: %i\n"
"duration: %1.3f\n",
duration.RoundS(),
duration.ToDoubleS());
r.Fmt(FMT_STRING("Time: {}\n"
"duration: {:1.3f}\n"),
duration.RoundS(),
duration.ToDoubleS());
}
void
@ -111,12 +116,15 @@ song_print_info(Response &r, const DetachedSong &song, bool base) noexcept
if (!IsNegative(song.GetLastModified()))
time_print(r, "Last-Modified", song.GetLastModified());
if (const auto &f = song.GetAudioFormat(); f.IsDefined())
r.Fmt(FMT_STRING("Format: {}\n"), f);
tag_print_values(r, song.GetTag());
const auto duration = song.GetDuration();
if (!duration.IsNegative())
r.Format("Time: %i\n"
"duration: %1.3f\n",
duration.RoundS(),
duration.ToDoubleS());
r.Fmt(FMT_STRING("Time: {}\n"
"duration: {:1.3f}\n"),
duration.RoundS(),
duration.ToDoubleS());
}

@ -22,8 +22,8 @@
#include "db/plugins/simple/Song.hxx"
#include "song/DetachedSong.hxx"
#include "TagSave.hxx"
#include "fs/io/TextFile.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "io/LineReader.hxx"
#include "io/BufferedOutputStream.hxx"
#include "tag/ParseName.hxx"
#include "tag/Tag.hxx"
#include "tag/Builder.hxx"
@ -63,6 +63,9 @@ song_save(BufferedOutputStream &os, const Song &song)
if (song.audio_format.IsDefined())
os.Format("Format: %s\n", ToString(song.audio_format).c_str());
if (song.in_playlist)
os.Write("InPlaylist: yes\n");
if (!IsNegative(song.mtime))
os.Format(SONG_MTIME ": %li\n",
(long)std::chrono::system_clock::to_time_t(song.mtime));
@ -85,9 +88,8 @@ song_save(BufferedOutputStream &os, const DetachedSong &song)
}
DetachedSong
song_load(TextFile &file, const char *uri,
std::string *target_r,
AudioFormat *audio_format_r)
song_load(LineReader &file, const char *uri,
std::string *target_r, bool *in_playlist_r)
{
DetachedSong song(uri);
@ -113,13 +115,11 @@ song_load(TextFile &file, const char *uri,
if (target_r != nullptr)
*target_r = value;
} else if (StringIsEqual(line, "Format")) {
if (audio_format_r != nullptr) {
try {
*audio_format_r =
ParseAudioFormat(value, false);
} catch (...) {
/* ignore parser errors */
}
try {
song.SetAudioFormat(ParseAudioFormat(value,
false));
} catch (...) {
/* ignore parser errors */
}
} else if (StringIsEqual(line, "Playlist")) {
tag.SetHasPlaylist(StringIsEqual(value, "yes"));
@ -135,6 +135,9 @@ song_load(TextFile &file, const char *uri,
song.SetStartTime(SongTime::FromMS(start_ms));
song.SetEndTime(SongTime::FromMS(end_ms));
} else if (StringIsEqual(line, "InPlaylist")) {
if (in_playlist_r != nullptr)
*in_playlist_r = StringIsEqual(value, "yes");
} else {
throw FormatRuntimeError("unknown line in db: %s", line);
}

@ -28,7 +28,7 @@ struct Song;
struct AudioFormat;
class DetachedSong;
class BufferedOutputStream;
class TextFile;
class LineReader;
void
song_save(BufferedOutputStream &os, const Song &song);
@ -43,8 +43,7 @@ song_save(BufferedOutputStream &os, const DetachedSong &song);
* Throws on error.
*/
DetachedSong
song_load(TextFile &file, const char *uri,
std::string *target_r=nullptr,
AudioFormat *audio_format_r=nullptr);
song_load(LineReader &file, const char *uri,
std::string *target_r=nullptr, bool *in_playlist_r=nullptr);
#endif

@ -153,9 +153,10 @@ DetachedSong::LoadFile(Path path)
return false;
TagBuilder tag_builder;
auto new_audio_format = AudioFormat::Undefined();
try {
if (!ScanFileTagsWithGeneric(path, tag_builder))
if (!ScanFileTagsWithGeneric(path, tag_builder, &new_audio_format))
return false;
} catch (...) {
// TODO: log or propagate I/O errors?
@ -163,6 +164,7 @@ DetachedSong::LoadFile(Path path)
}
mtime = fi.GetModificationTime();
audio_format = new_audio_format;
tag_builder.Commit(tag);
return true;
}
@ -177,9 +179,11 @@ DetachedSong::Update()
return LoadFile(path_fs);
} else if (IsRemote()) {
TagBuilder tag_builder;
auto new_audio_format = AudioFormat::Undefined();
try {
if (!tag_stream_scan(uri.c_str(), tag_builder))
if (!tag_stream_scan(uri.c_str(), tag_builder,
&new_audio_format))
return false;
} catch (...) {
// TODO: log or propagate I/O errors?
@ -187,6 +191,7 @@ DetachedSong::Update()
}
mtime = std::chrono::system_clock::time_point::min();
audio_format = new_audio_format;
tag_builder.Commit(tag);
return true;
} else

@ -22,12 +22,11 @@
#include "output/State.hxx"
#include "queue/PlaylistState.hxx"
#include "fs/io/TextFile.hxx"
#include "fs/io/FileOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "io/FileOutputStream.hxx"
#include "io/BufferedOutputStream.hxx"
#include "storage/StorageState.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "mixer/Volume.hxx"
#include "SongLoader.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
@ -47,7 +46,7 @@ StateFile::StateFile(StateFileConfig &&_config,
void
StateFile::RememberVersions() noexcept
{
prev_volume_version = sw_volume_state_get_hash();
prev_volume_version = partition.mixer_memento.GetSoftwareVolumeStateHash();
prev_output_version = audio_output_state_get_version();
prev_playlist_version = playlist_state_get_hash(partition.playlist,
partition.pc);
@ -59,7 +58,7 @@ StateFile::RememberVersions() noexcept
bool
StateFile::IsModified() const noexcept
{
return prev_volume_version != sw_volume_state_get_hash() ||
return prev_volume_version != partition.mixer_memento.GetSoftwareVolumeStateHash() ||
prev_output_version != audio_output_state_get_version() ||
prev_playlist_version != playlist_state_get_hash(partition.playlist,
partition.pc)
@ -72,7 +71,7 @@ StateFile::IsModified() const noexcept
inline void
StateFile::Write(BufferedOutputStream &os)
{
save_sw_volume_state(os);
partition.mixer_memento.SaveSoftwareVolumeState(os);
audio_output_state_save(os, partition.outputs);
#ifdef ENABLE_DATABASE
@ -93,8 +92,8 @@ StateFile::Write(OutputStream &os)
void
StateFile::Write()
{
FormatDebug(state_file_domain,
"Saving state file %s", path_utf8.c_str());
FmtDebug(state_file_domain,
"Saving state file {}", path_utf8);
try {
FileOutputStream fos(config.path);
@ -112,7 +111,7 @@ StateFile::Read()
try {
bool success;
FormatDebug(state_file_domain, "Loading state file %s", path_utf8.c_str());
FmtDebug(state_file_domain, "Loading state file {}", path_utf8);
TextFile file(config.path);
@ -125,7 +124,7 @@ try {
const char *line;
while ((line = file.ReadLine()) != nullptr) {
success = read_sw_volume_state(line, partition.outputs) ||
success = partition.mixer_memento.LoadSoftwareVolumeState(line, partition.outputs) ||
audio_output_state_read(line, partition.outputs) ||
playlist_state_restore(config, line, file, song_loader,
partition.playlist,
@ -135,9 +134,9 @@ try {
#endif
if (!success)
FormatError(state_file_domain,
"Unrecognized line in state file: %s",
line);
FmtError(state_file_domain,
"Unrecognized line in state file: {}",
line);
}
RememberVersions();
@ -148,7 +147,7 @@ try {
void
StateFile::CheckModified() noexcept
{
if (!timer_event.IsActive() && IsModified())
if (!timer_event.IsPending() && IsModified())
timer_event.Schedule(config.interval);
}

@ -21,8 +21,7 @@
#define MPD_STATE_FILE_HXX
#include "StateFileConfig.hxx"
#include "event/TimerEvent.hxx"
#include "util/Compiler.h"
#include "event/FarTimerEvent.hxx"
#include "config.h"
#include <string>
@ -36,7 +35,7 @@ class StateFile final {
const std::string path_utf8;
TimerEvent timer_event;
FarTimerEvent timer_event;
Partition &partition;
@ -76,7 +75,7 @@ private:
* Check if MPD's state was modified since the last
* RememberVersions() call.
*/
gcc_pure
[[gnu::pure]]
bool IsModified() const noexcept;
/* callback for #timer_event */

@ -32,7 +32,7 @@ StateFileConfig::StateFileConfig(const ConfigData &config)
{
#ifdef ANDROID
if (path.IsNull()) {
const auto cache_dir = GetUserCacheDir();
const auto cache_dir = GetAppCacheDir();
if (cache_dir.IsNull())
return;

@ -34,6 +34,8 @@
#include "system/Clock.hxx"
#endif
#include <fmt/format.h>
#include <chrono>
#ifndef _WIN32
@ -97,19 +99,19 @@ db_stats_print(Response &r, const Database &db)
unsigned total_duration_s =
std::chrono::duration_cast<std::chrono::seconds>(stats.total_duration).count();
r.Format("artists: %u\n"
"albums: %u\n"
"songs: %u\n"
"db_playtime: %u\n",
stats.artist_count,
stats.album_count,
stats.song_count,
total_duration_s);
r.Fmt(FMT_STRING("artists: {}\n"
"albums: {}\n"
"songs: {}\n"
"db_playtime: {}\n"),
stats.artist_count,
stats.album_count,
stats.song_count,
total_duration_s);
const auto update_stamp = db.GetUpdateStamp();
if (!IsNegative(update_stamp))
r.Format("db_update: %lu\n",
(unsigned long)std::chrono::system_clock::to_time_t(update_stamp));
r.Fmt(FMT_STRING("db_update: {}\n"),
std::chrono::system_clock::to_time_t(update_stamp));
}
#endif
@ -123,10 +125,10 @@ stats_print(Response &r, const Partition &partition)
const auto uptime = std::chrono::steady_clock::now() - start_time;
#endif
r.Format("uptime: %u\n"
"playtime: %lu\n",
(unsigned)std::chrono::duration_cast<std::chrono::seconds>(uptime).count(),
lround(partition.pc.GetTotalPlayTime().count()));
r.Fmt(FMT_STRING("uptime: {}\n"
"playtime: {}\n"),
std::chrono::duration_cast<std::chrono::seconds>(uptime).count(),
lround(partition.pc.GetTotalPlayTime().count()));
#ifdef ENABLE_DATABASE
const Database *db = partition.instance.GetDatabase();

@ -21,19 +21,29 @@
#include "TagStream.hxx"
#include "TagFile.hxx"
#include "tag/Generic.hxx"
#include "song/LightSong.hxx"
#include "db/Interface.hxx"
#include "storage/StorageInterface.hxx"
#include "client/Client.hxx"
#include "protocol/Ack.hxx"
#include "fs/AllocatedPath.hxx"
#include "input/InputStream.hxx"
#include "util/Compiler.h"
#include "util/ScopeExit.hxx"
#include "util/StringCompare.hxx"
#include "util/UriExtract.hxx"
#include "LocateUri.hxx"
static void
TagScanStream(const char *uri, TagHandler &handler)
{
if (!tag_stream_scan(uri, handler))
Mutex mutex;
auto is = InputStream::OpenReady(uri, mutex);
if (!tag_stream_scan(*is, handler))
throw ProtocolError(ACK_ERROR_NO_EXIST, "Failed to load file");
ScanGenericTags(*is, handler);
}
static void
@ -45,10 +55,67 @@ TagScanFile(const Path path_fs, TagHandler &handler)
ScanGenericTags(path_fs, handler);
}
#ifdef ENABLE_DATABASE
/**
* Collapse "../" prefixes in a URI relative to the specified base
* URI.
*/
static std::string
ResolveUri(std::string_view base, const char *relative)
{
while (true) {
const char *rest = StringAfterPrefix(relative, "../");
if (rest == nullptr)
break;
if (base == ".")
throw ProtocolError(ACK_ERROR_NO_EXIST, "Bad real URI");
base = PathTraitsUTF8::GetParent(base);
relative = rest;
}
return PathTraitsUTF8::Build(base, relative);
}
/**
* Look up the specified song in the database and return its
* (resolved) "real" URI.
*/
static std::string
GetRealSongUri(Client &client, std::string_view uri)
{
const auto &db = client.GetDatabaseOrThrow();
const auto *song = db.GetSong(uri);
if (song == nullptr)
throw ProtocolError(ACK_ERROR_NO_EXIST, "No such song");
AtScopeExit(&db, song) { db.ReturnSong(song); };
if (song->real_uri == nullptr)
return {};
return ResolveUri(PathTraitsUTF8::GetParent(uri), song->real_uri);
}
#endif
static void
TagScanDatabase(Client &client, const char *uri, TagHandler &handler)
{
#ifdef ENABLE_DATABASE
const auto real_uri = GetRealSongUri(client, uri);
if (!real_uri.empty()) {
uri = real_uri.c_str();
// TODO: support absolute paths?
if (uri_has_scheme(uri))
return TagScanStream(uri, handler);
}
const Storage *storage = client.GetStorage();
if (storage == nullptr) {
#else

@ -23,26 +23,28 @@
#include "client/Response.hxx"
#include "util/StringView.hxx"
#include <fmt/format.h>
void
tag_print_types(Response &r) noexcept
{
const auto tag_mask = global_tag_mask & r.GetTagMask();
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++)
if (tag_mask.Test(TagType(i)))
r.Format("tagtype: %s\n", tag_item_names[i]);
r.Fmt(FMT_STRING("tagtype: {}\n"), tag_item_names[i]);
}
void
tag_print(Response &r, TagType type, StringView value) noexcept
tag_print(Response &r, TagType type, StringView _value) noexcept
{
r.Format("%s: %.*s\n", tag_item_names[type],
int(value.size), value.data);
const std::string_view value{_value};
r.Fmt(FMT_STRING("{}: {}\n"), tag_item_names[type], value);
}
void
tag_print(Response &r, TagType type, const char *value) noexcept
{
r.Format("%s: %s\n", tag_item_names[type], value);
r.Fmt(FMT_STRING("{}: {}\n"), tag_item_names[type], value);
}
void
@ -58,10 +60,10 @@ void
tag_print(Response &r, const Tag &tag) noexcept
{
if (!tag.duration.IsNegative())
r.Format("Time: %i\n"
"duration: %1.3f\n",
tag.duration.RoundS(),
tag.duration.ToDoubleS());
r.Fmt(FMT_STRING("Time: {}\n"
"duration: {:1.3f}\n"),
tag.duration.RoundS(),
tag.duration.ToDoubleS());
tag_print_values(r, tag);
}

@ -19,7 +19,7 @@
#include "TagSave.hxx"
#include "tag/Tag.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "io/BufferedOutputStream.hxx"
#define SONG_TIME "Time: "

@ -36,10 +36,10 @@
gcc_pure
static bool
CheckDecoderPlugin(const DecoderPlugin &plugin,
const char *suffix, const char *mime) noexcept
std::string_view suffix, std::string_view mime) noexcept
{
return (mime != nullptr && plugin.SupportsMimeType(mime)) ||
(suffix != nullptr && plugin.SupportsSuffix(suffix));
return (!mime.empty() && plugin.SupportsMimeType(mime)) ||
(!suffix.empty() && plugin.SupportsSuffix(suffix));
}
bool
@ -47,25 +47,24 @@ tag_stream_scan(InputStream &is, TagHandler &handler)
{
assert(is.IsReady());
UriSuffixBuffer suffix_buffer;
const char *const suffix = uri_get_suffix(is.GetURI(), suffix_buffer);
const char *mime = is.GetMimeType();
const auto suffix = uri_get_suffix(is.GetURI());
const char *full_mime = is.GetMimeType();
if (suffix == nullptr && mime == nullptr)
if (suffix.empty() && full_mime == nullptr)
return false;
std::string mime_base;
if (mime != nullptr)
mime = (mime_base = GetMimeTypeBase(mime)).c_str();
std::string_view mime_base{};
if (full_mime != nullptr)
mime_base = GetMimeTypeBase(full_mime);
return decoder_plugins_try([suffix, mime, &is,
return decoder_plugins_try([suffix, mime_base, &is,
&handler](const DecoderPlugin &plugin){
try {
is.LockRewind();
} catch (...) {
}
return CheckDecoderPlugin(plugin, suffix, mime) &&
return CheckDecoderPlugin(plugin, suffix, mime_base) &&
plugin.ScanStream(is, handler);
});
}

@ -20,6 +20,9 @@
#include "TimePrint.hxx"
#include "client/Response.hxx"
#include "time/ISO8601.hxx"
#include "util/StringBuffer.hxx"
#include <fmt/format.h>
void
time_print(Response &r, const char *name,
@ -33,5 +36,5 @@ time_print(Response &r, const char *name,
return;
}
r.Format("%s: %s\n", name, s.c_str());
r.Fmt(FMT_STRING("{}: {}\n"), name, s.c_str());
}

@ -30,10 +30,6 @@ class AudioManager : public Java::GlobalObject {
public:
AudioManager(JNIEnv *env, jobject obj) noexcept;
AudioManager(std::nullptr_t) noexcept { maxVolume = 0; }
~AudioManager() noexcept {}
int GetMaxVolume() { return maxVolume; }
int GetVolume(JNIEnv *env);
void SetVolume(JNIEnv *env, int);

@ -26,17 +26,42 @@
#include "AudioManager.hxx"
static jmethodID getExternalFilesDir_method,
getCacheDir_method,
getSystemService_method;
void
Context::Initialise(JNIEnv *env) noexcept
{
Java::Class cls{env, "android/content/Context"};
getExternalFilesDir_method = env->GetMethodID(cls, "getExternalFilesDir",
"(Ljava/lang/String;)Ljava/io/File;");
getCacheDir_method = env->GetMethodID(cls, "getCacheDir",
"()Ljava/io/File;");
getSystemService_method = env->GetMethodID(cls, "getSystemService",
"(Ljava/lang/String;)Ljava/lang/Object;");
}
AllocatedPath
Context::GetExternalFilesDir(JNIEnv *env, const char *type) noexcept
{
assert(type != nullptr);
jobject file = env->CallObjectMethod(Get(), getExternalFilesDir_method,
Java::String::Optional(env, type).Get());
if (Java::DiscardException(env) || file == nullptr)
return nullptr;
return Java::File::ToAbsolutePath(env, file);
}
AllocatedPath
Context::GetCacheDir(JNIEnv *env) const noexcept
{
assert(env != nullptr);
Java::Class cls(env, env->GetObjectClass(Get()));
jmethodID method = env->GetMethodID(cls, "getCacheDir",
"()Ljava/io/File;");
assert(method);
jobject file = env->CallObjectMethod(Get(), method);
jobject file = env->CallObjectMethod(Get(), getCacheDir_method);
if (Java::DiscardException(env) || file == nullptr)
return nullptr;
@ -48,13 +73,8 @@ Context::GetAudioManager(JNIEnv *env) noexcept
{
assert(env != nullptr);
Java::Class cls(env, env->GetObjectClass(Get()));
jmethodID method = env->GetMethodID(cls, "getSystemService",
"(Ljava/lang/String;)Ljava/lang/Object;");
assert(method);
Java::String name(env, "audio");
jobject am = env->CallObjectMethod(Get(), method, name.Get());
jobject am = env->CallObjectMethod(Get(), getSystemService_method, name.Get());
if (Java::DiscardException(env) || am == nullptr)
return nullptr;

@ -27,13 +27,26 @@ class AudioManager;
class Context : public Java::GlobalObject {
public:
/**
* Global initialisation. Looks up the methods of the
* Context Java class.
*/
static void Initialise(JNIEnv *env) noexcept;
Context(JNIEnv *env, jobject obj) noexcept
:Java::GlobalObject(env, obj) {}
gcc_pure
/**
* @param type the subdirectory name; may be nullptr
*/
[[gnu::pure]]
AllocatedPath GetExternalFilesDir(JNIEnv *env,
const char *type=nullptr) noexcept;
[[gnu::pure]]
AllocatedPath GetCacheDir(JNIEnv *env) const noexcept;
gcc_pure
[[gnu::pure]]
AudioManager *GetAudioManager(JNIEnv *env) noexcept;
};

Some files were not shown because too many files have changed in this diff Show More