Compare commits

..

1850 Commits

Author SHA1 Message Date
af649ae85f Document SELinux-blocked io_uring failures 2025-03-14 22:15:29 -04:00
30e1cbbcba fs/glue/StandardDirectory: Add standard directories for macOS 2025-03-14 08:25:30 +01:00
86ab4bc62c config/Path: Always allow getting of XDG... variables 2025-03-13 22:22:14 +01:00
a34bf3588e fs/glue/StandardDirectory: Remove double import 2025-03-13 22:21:15 +01:00
64c9e5a2d4 .gitignore: remove tool-specific patterns
If somebody uses tools that create these files, they should put them
in their global gitignore.
2025-03-13 14:55:09 +01:00
9f02a88d19 .github/workflows: add more paths-ignore 2025-03-13 14:53:17 +01:00
e6a25e7e0b doc/conf.py: use "sphinx_rtd_theme" only if it is installed
Don't fail at build time only because the RTD scheme is not installed.
Such a problem should be detected at configure time.
2025-03-13 14:44:23 +01:00
f6337dd95e doc/conf.py: remove the "~git" version suffix in the 0.24 stable branch 2025-03-13 14:19:32 +01:00
42fc26cc6d .github/workflows/build_android.yml: switch to the installed NDK r27 2025-03-13 11:33:46 +01:00
1b6567b31b test/net/TestIPv[46]Address: initialize WinSock for some of the tests
Not necessary with WINE, but the "real" Windows seems to be picky
about this.
2025-03-13 11:26:05 +01:00
171bb9b737 test/TestStringFilter: enable another failing test on Windows 2025-03-13 11:25:57 +01:00
3626d4ec9a Revert "lib/icu/Compare: add LINGUISTIC_IGNORECASE [Windows]"
This reverts commit 1bd204527e.  This
fixes a test on WINE, but fails many others on Windows.  D'oh!
2025-03-13 11:22:02 +01:00
71c8f4de40 test/TestStringFilter: disable two failing checks on Windows 2025-03-13 10:37:01 +01:00
1bd204527e lib/icu/Compare: add LINGUISTIC_IGNORECASE [Windows]
This fixes one check in the "StringFilterTest.Normalize" unit test.
2025-03-13 10:35:42 +01:00
9b25d59120 test/TestStringFilter: re-enable two tests on Windows
These don't fail anymore.  I don't know what has changed since these
`#ifndefs` were added by commit d7f545721b
2025-03-13 10:35:33 +01:00
ca5580a560 test/util/TestIntrusiveTreeSet: do not add duplicates in the LargeRandom tests
This can fail randomly if the order of identical values is different
in the std::deque and the IntrusiveTreeSet.
2025-03-13 09:55:01 +01:00
dd59db2be2 fs/LookupFile: check for empty file name on Windows
Fixes crash bug in the (synthetic) unit test.  See code comment.
2025-03-13 09:21:04 +01:00
c290e0b965 LogBackend: remove the colon after the time stamp
This colon with spaces around it looked weird and was somewhat
redundant.  Let's use a space only.  This looks better if we replace
the space between date and time with a 'T', so it's mostly the ISO8601
format only in local time instead of UTC.
2025-03-13 09:02:01 +01:00
689d231809 LogBackend: include year in time stamp
Also use a numeric month instead of the month name.
2025-03-13 09:00:37 +01:00
84ff3c6a0d LogBackend: use %T 2025-03-13 08:58:36 +01:00
093122aaeb LogBackend: use fmt to format the time stamp 2025-03-13 08:57:23 +01:00
4f981adb97 lib/fmt/Unsafe: new library 2025-03-13 08:55:12 +01:00
3945b808a2 CommandLine: update copyright year 2025-03-13 08:30:28 +01:00
a171a588cf queue/QueuePrint: switch to SPDX header 2025-03-13 08:30:28 +01:00
2388f38d7d NEWS: mention the id3tag build failure fix merged from the obsolete v0.23.x branch 2025-03-13 08:30:28 +01:00
dac2c4df9b output/plugins/SndioOutputPlugin: Fix sndio volume calculation
This commit addresses issues  and .
MPD and sndio volume ranges being different, the formula to transform a
value from one set to the other is in the form of `(a * x + b) / c`
where:
 - a = output set max value
 - b = adjustment term
 - c = input set max value
Previous calculation formula had `b = 0`, scaling values too low and
rendering increment impossible. Having `b = out_maxval / 2` balances the
transformation, ensuring a better spread of values across the output
range.

Closes 
2025-03-12 12:24:00 +01:00
843cb1604d net: delete UniqueSocketDescriptor.hxx.orig
This got committed accidently.
2025-03-11 17:16:58 +01:00
59c289c7d8 README.md: update manual and forum links
It's on readthedocs and GitHub now.
2025-03-11 13:03:28 +01:00
4b85bb57cc Merge branch 'v0.23.x' 2025-03-11 12:52:05 +01:00
a19b6919e0 increment version number to 0.24.1 2025-03-11 11:24:59 +01:00
1caeb9b418 release v0.24 2025-03-11 11:05:29 +01:00
d3717c5b81 test/util/TestIntrusiveTreeSet: add test with all-zero items 2025-03-11 10:45:33 +01:00
90987194cb .github/workflows/build.yml: run unit tests on Windows
The unit tests currently fail on Windows.  That needs to be fixed, but
good to know that there are problems currently.
2025-03-11 10:18:19 +01:00
2953737478 .github/workflows/build.yml: remove "warning_level=3", it is the default 2025-03-11 10:11:06 +01:00
ac3a5e27ec .github/workflows/build.yml: split "Compile and Test" into two steps 2025-03-11 10:11:06 +01:00
4ae89b7b4a .github/workflows/build.yml: enable ccache for Windows builds 2025-03-11 10:11:06 +01:00
568494440f .github/workflows/build.yml: add matrix.os to ccache key 2025-03-11 10:11:06 +01:00
5d0aeda4e9 .github/workflows/build.yml: run unit tests with "--print-errorlogs"
With this option, Meson prints errors instead of logging them to a
file (that would be inaccessible).
2025-03-11 10:11:06 +01:00
d89b9d1683 test/fs/TestParsePath: include "fs/XDG.hxx" for USE_XDG 2025-03-11 10:09:52 +01:00
c7c4e7a6bf python/build/libs.py: update libopenmpt to 0.7.13 2025-03-11 09:26:13 +01:00
1c7c2026db config/Path: check for empty XDG variables 2025-03-11 09:23:33 +01:00
a9805db500 config/Path: move code to GetVariable() 2025-03-11 09:19:20 +01:00
e8a4317f31 config/Path: simplify tilde expansion 2025-03-11 09:17:01 +01:00
f4f5e94a36 config/Path: pass std::string_view to ParsePath() 2025-03-11 09:15:18 +01:00
b2326b9a98 test/fs/TestParsePath: unit test for ParsePath() 2025-03-11 09:13:31 +01:00
1dc8cd8eef config/Path: allow expanding $HOME even without XDG 2025-03-11 08:45:04 +01:00
147fe18ad6 config/Path: adjust error message (not an environment variable) 2025-03-11 08:44:18 +01:00
6fd6a5110c config/Path: use string_view literals 2025-03-11 08:36:57 +01:00
e8ce417150 Initial support for $HOME and some XDG variables inside the configuration file
This commit tries to address issues  and . It enables the path expansion of HOME, XDG_CONFIG_HOME, XDG_MUSIC_DIR, XDG_CACHE_HOME and XDG_RUNTIME_DIR by using the glue functions already available in MPD.

Signed-off-by: Joan Vilardaga <github-91yu@joanvc.cat>
2025-03-10 22:21:03 +01:00
da40483666 event/Loop: destroy the UringWake instance in DisableUring() 2025-03-10 19:14:10 +01:00
06bc373ace event/Loop: read eventfd with io_uring
This eliminates a roundtrip to epoll.
2025-03-10 18:59:08 +01:00
7797158ea6 event/Loop: auto-restart io_uring_prep_poll_multishot()
Applications need to check the `IORING_CQE_F_MORE` flag to see whether
the kernel is still polling, or whether it has stopped for some reason.
2025-03-10 18:52:31 +01:00
01a04baf7b util/DivideString: remove unused library 2025-03-10 18:35:20 +01:00
46b461df42 playlist/pls: migrate the line parser to use std::string_view 2025-03-10 18:35:20 +01:00
898e0a2bc4 test/playlist: unit tests for the playlist plugins
Only "pls" for now.
2025-03-10 18:35:20 +01:00
2d3271859f input/memory: new implementation (for unit tests) 2025-03-10 18:17:33 +01:00
b6672004bc util/StringCompare: add SkipPrefixIgnoreCase() 2025-03-10 18:17:33 +01:00
eafca183a6 input/meson.build: add libinput_basic.a
This is the middle ground between libinput_api.a (the raw API) and
libinput_glue.a (dependencies on all plugins).
2025-03-10 17:13:51 +01:00
59f9e0ca70 input/meson.build: do not compile ProxyInputStream.cxx twice 2025-03-10 17:11:12 +01:00
800a03f0dc playlist/plugins/meson.build: add missing dependencies 2025-03-10 14:33:41 +01:00
55c11448ff util/NumberParser: add ParseIntegerTo()
An version of the function without the `std::optional` overhead.
2025-03-10 14:04:50 +01:00
e9c1ea684b util/NumberParser: add std::from_chars() wrapper taking std::string_view 2025-03-10 14:04:50 +01:00
103487e8ad event/InotifyEvent: add method IsDefined() 2025-03-10 14:04:50 +01:00
fb59bbc481 python/build/libs.py: update FFmpeg to 7.1.1 2025-03-10 14:04:50 +01:00
d0f6aa5b87 subprojects: update libnpupnp to 6.2.1-1 2025-03-10 14:04:12 +01:00
fdb8874803 python/build/libs.py: update libnfs to 6.0.2 2025-02-28 19:47:57 +01:00
c9a22b3404 meson.build: disable unnecessary libsndfile features 2025-02-28 19:41:19 +01:00
fc5d10b776 subprojects: add libsndfile.wrap 2025-02-28 19:37:17 +01:00
4cefb30dd9 decoder/flac: ignore FLAC__STREAM_DECODER_END_OF_LINK (FLAC 1.5)
Fixes -Wswitch compiler warning when building with FLAC 1.5.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2219
2025-02-28 10:32:47 +01:00
36482f5e6a subprojects: update gtest to 1.15.2-2 2025-02-28 09:59:07 +01:00
d822685c53 config/File: support resetting repeatable params
This allows resetting bind_to_address to override the default value in a
included config.
2025-02-21 13:52:44 +01:00
9d87fb5e09 subprojects: update sqlite3 to 3.49.1-1 2025-02-20 13:59:06 +01:00
85014b5fa2 event/Loop: move code to Wait() 2025-02-13 16:54:36 +01:00
aff929dbd6 event/Loop: rename Wait() to Poll()
Preparing to have another Wait() method wrapping Poll() and io_uring.
2025-02-13 16:53:49 +01:00
dda85e02bf io/Open: add TryOpen(struct open_how), Open(struct open_how) 2025-02-13 16:09:12 +01:00
5b393052ee event/Loop: pass timeout=nullptr to io_uring if there is no timer 2025-02-13 16:04:07 +01:00
624da8ce5b event/Loop: use io_uring_prep_poll_multishot() on the epoll fd
This wraps epoll and io_uring the other way: previously, we had the
io_uring file descriptor registered in epoll and when it became ready,
we could query its completion ring.  The problem is that the poll
wakeups cause considerable overhead in the Linux kernel, see
https://lore.kernel.org/io-uring/20250128133927.3989681-9-max.kellermann@ionos.com/

By wrapping epoll inside io_uring using
io_uring_prep_poll_multishot(), the "outer" loop is io_uring and
inside it, we have epoll.  This adds another system call for epoll,
but that will go away as soon as most operations are going through
io_uring.  Previously, io_uring had this extra system call.
2025-02-13 16:02:40 +01:00
bca9e3e347 io/uring/Queue: dispatch all completions in SubmitAndWaitDispatchOneCompletion()
io_uring_submit_and_wait_timeout() can return multiple completions,
even if we wait for only one.  We should dispatch them all or we miss
wakeups.
2025-02-13 14:53:30 +01:00
2276ebd70f io/uring/Queue: add DispatchCompletions() overload using io_uring_for_each_cqe() 2025-02-13 14:53:24 +01:00
a9bee1c64b io/uring/Ring: add io_uring_for_each_cqe() wrapper 2025-02-13 14:53:17 +01:00
c8e88408b2 io/uring/Ring: ignore EINTR 2025-02-13 14:53:11 +01:00
45644759fe io/uring/CancellableOperation: invoke OnUringCompletion() in destructor
This is important for operations that have complex cancellation
procedures (e.g. if they need to free buffers).  They might leave an
Operation instance in the queue.
2025-02-13 14:52:52 +01:00
e014d31972 io/uring/Ring: add io_uring_submit_and_wait_timeout() wrapper 2025-02-13 14:52:37 +01:00
b7655d38f7 io/uring/Queue: support IORING_CQE_F_MORE 2025-02-13 14:52:30 +01:00
268f737ac4 meson.build: suppress -Wmissing-field-initializers
There's nothing wrong with initializing only some fields.
2025-02-13 14:21:38 +01:00
80ff0a062a system/EpollFD: add method GetFileDescriptor() 2025-02-13 14:19:28 +01:00
24bcf44a47 subprojects: update sqlite to 3.49.0-1 2025-02-13 14:12:53 +01:00
gd
f1e43cb498 android: Loader - load early (before service thread) both in activity and service.
Loader converted from java to kotlin.

Instead of loading libmpd when the service thread is started,
the service will not start the the thread if libmpd failed to load.

The loader is also accessed by the view data to let
the ui adjust if failed to load, by showing the failure reason
and disabling the Start MPD button.
2025-02-06 14:23:26 +02:00
gd
ae1c5e3424 android: build.gradle - added build flavor "fail-test" to test System.loadLibrary("mpd") failure 2025-02-06 14:11:06 +02:00
gd
9eb5879542 android: IntentUtils - added license comment 2025-02-06 14:06:53 +02:00
gd
038759506f android: added 'universal' flavor that includes both both arm64-v8a and x86_64 versions of libmpd.so 2025-02-05 20:31:43 +02:00
gd
2bf9fdf10e android: migrated build to version catalogs
For easier management of dependencies versions: https://developer.android.com/build/migrate-to-catalogs
2025-02-05 20:15:58 +02:00
gd
0bf77f4eb3 android: converted Main from java to kotlin 2025-02-05 11:20:39 +02:00
gd
034bcf4f44 android: added product flavors to separatly build apk for arm64-v8a or x86_64 2025-02-04 10:23:26 +02:00
gd
834d6dcf46 android: build version of kotlin and compose updated.
Changed to compatible versions according to https://developer.android.com/jetpack/androidx/releases/compose-kotlin#kts
2025-02-04 10:22:57 +02:00
gd
8a642c8a83 android: MainScreen - use Icons.AutoMirrored.Filled.List instead of deprecated Icons.Default.List 2025-02-04 10:22:57 +02:00
gd
fe42ad2439 android: .gitignore - added previously misspelled app/src/main/jniLibs/ 2025-02-04 10:22:57 +02:00
gd
51242be72b android: changed permissions handling UI in status screen when show rationale is false
Android will ignore permission request and will not show the request dialog
if the user's action implies "don't ask again."
This leaves the app in a crippled state and the user confused.
Google says "don't try to convince the user", so it returns false for `shouldShowRequestPermissionRationale`.

To help the user proceed, we show the `Request permission` button only if `shouldShowRequestPermissionRationale == true`
because there's a good chance the premission request dialog will not be ignored.

If `shouldShowRequestPermissionRationale == false` we instead show the "rationale" message and a button to open
the app info dialog where the user can explicitly grand the permission.
2025-02-04 10:22:57 +02:00
gd
cb62aff43e android: added missing package declaration in SettingsScreen.kt 2025-02-04 10:22:57 +02:00
gd
491e726540 android: manifest - added sdk version to legacy permission READ_EXTERNAL_STORAGE, added permission READ_MEDIA_AUDIO
Change fo r SDK version 33 and above
2025-02-04 10:22:57 +02:00
gd
7404be41dc android: git ignoring .idea directory completely until a good reason emerges not to 2025-02-04 10:22:57 +02:00
b8289ae923 input/meson.build: Add missing dependency 2025-02-03 23:07:58 +01:00
6b92b7adb9 util/PacketBigEndian: add operator| 2025-02-01 19:30:17 +01:00
00a352ffcd event/Loop: explicit io_uring initialization
Log the io_uring initialization error at MPD startup.
2025-02-01 19:20:50 +01:00
63cc07b8a7 event/Loop: add method SetThread()
Require to call it before calling Run(); remove the setter from Run().
This gives class EventThread more control over when it is initialized.
2025-02-01 19:19:59 +01:00
b2bf95009b event/Thread: use inline initializers 2025-02-01 18:24:02 +01:00
gd
7df041310c android: build.gradle.kts - updated dependencies versions. Updated compile sdk to 35, and target sdk to 34 2025-02-01 18:09:12 +01:00
gd
cd9522c1d1 android: manifest - added android:foregroundServiceType=mediaPlayback and permission FOREGROUND_SERVICE_MEDIA_PLAYBACK
Required by newer android sdk.
2025-02-01 18:09:07 +01:00
gd
59bd0fe0f0 android: added README.md for notes and resources for MPD android maintainers. 2025-02-01 18:09:02 +01:00
gd
0872a761c8 android: gradle build - add ndk.abiFilters to package the prebuilt arm64-v8a/libmpd.so with the apk 2025-02-01 18:08:58 +01:00
gd
996e158f56 android: updated gradle version 2025-02-01 18:08:55 +01:00
gd
7fb195bc0b android: Context.cxx - in GetExternalFilesDir removed assert type != nullptr
May be null for the root of the files directory.
2025-02-01 18:08:52 +01:00
gd
2fabaa2e95 android: meson.build - changed output dir name from jnilibs to jniLibs
It is the default name: https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs
2025-02-01 18:08:48 +01:00
e3cf9bb0a1 Fix deamon mode on macos 2025-02-01 18:05:49 +01:00
407db96d4a Install some more dependencies in the macos workflow 2025-02-01 18:05:42 +01:00
3689200b78 Add prcr2 dependency to macos workflow 2025-02-01 18:05:34 +01:00
6c16430a85 Remove whitespace 2025-02-01 18:05:24 +01:00
ff37d11610 Workflow fixes for macOS 2025-02-01 18:05:17 +01:00
509786cbf1 Revert "remove macOS support"
This reverts commit 518ce0187a.
2025-02-01 18:05:13 +01:00
148050898a doc/user: update windows build meson version 2025-02-01 12:16:38 +03:00
a29d3eb975 Merge branch 'id3tag-meson-fix' of https://github.com/allixx/MPD into v0.23.x 2025-02-01 08:23:12 +01:00
1247ee5347 subprojects/packagefiles/id3tag/meson.build: fix meson errors 2025-02-01 09:59:40 +03:00
gd
f15b6a43d3 Logging: curl - write debug output through MPD log instead of curl writing directly to stderr.
The output gets the standard MPD log format with domain curl and a timestamp.
Using CURLOPT_DEBUGFUNCTION that is only called when CURLOPT_VERBOSE is in effect
when MPD log level is verbose.
2025-02-01 08:53:38 +02:00
bddfff9c2b meson.build: fix typo 2025-01-31 19:51:00 +01:00
cdc99812c9 python/build/libs.py: replace broken Boost 1.81.0 url 2025-01-31 19:17:28 +03:00
63ad12bb89 storage/nfs: MapUTF8("") returns the full URL including parameters
Closes https://github.com/MusicPlayerDaemon/MPD/issues/2154
2025-01-30 20:04:19 +01:00
7c4ddb5943 input/uring: initialize uring_input_queue lazily
The BlockingCall() in InitUringInputPlugin() did not work because the
EventThread was not yet started.  This was never noticed until commit
e309941646 which enabled `IORING_SETUP_SINGLE_ISSUER`, and suddenly
the kernel refused to accept io_uring_submit() calls from the
io_thread because io_uring_setup() had been called from the main
thread.
2025-01-30 20:00:57 +01:00
3cf5354e3f Revert "Main: start IO threads before initializing the rest"
This reverts commit abc8420697.  This
was a bad idea, too, because it broke daemonization.
2025-01-30 19:58:15 +01:00
838398103c Revert "event/Thread: start the thread in the constructor"
This reverts commit b49cfe96f4.  It was
a bad idea because it broke signal handlers.  I need to find a better
way to fix io_uring intialization.
2025-01-30 19:58:15 +01:00
30bd70939a lib/nfs/Connection: remove unnecessary include 2025-01-30 17:24:20 +01:00
275cd9d1d0 lib/nfs/Connection: give up connection after NFS4ERR_EXPIRED
Once a NFS request fails with NFS4ERR_EXPIRED, the whole connection is
broken and we need to open a new one.  I wish libnfs would report this
to us as a connection-level error, but instead only the one request
fails; therefore this workaround is an ugly kludge.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2175
2025-01-30 17:23:39 +01:00
5b001957c7 input/async: skip resume and seek if there is a pending error
The resume/seek was received asynchronously and meanwhile an error
might have occurred that needs to be handled.

This fixes another NFS-related crash bug.
2025-01-30 16:47:51 +01:00
d1e5c90c3b decoder/flac: do not seek when DecoderCommand::STOP is received
libFLAC tries to keep on seeking a stream even after a (fatal) read
error has occurred.  Let the DecoderClient decide whether proceeding
is possible.

This fixes a crash bug when playing a file over NFS and the NFS
connection fails.
2025-01-30 16:46:04 +01:00
715ef846b6 input/Plugin: pass URI as std::string_view 2025-01-30 13:38:30 +01:00
aee49d1c1c input/cdio: pass std::string_view to parse_cdio_uri() 2025-01-30 13:17:47 +01:00
459390cd56 input/alsa: use std::string_view in class SourceSpec 2025-01-30 13:03:52 +01:00
7ca8dedb35 pcm/AudioParser: use std::string_view 2025-01-30 12:27:20 +01:00
f6cee35896 fs/Traits: add IsAbsolute(string_view) 2025-01-30 11:55:44 +01:00
gd
66ee03741d Logging: enable log timestamp to stdout logging
When running with stdout output to debug the server
or misbehaving clients, it is useful to have the timestamp
to detect timing issues and response times.
Especially when opening and playing online sources that
block the connection thread sometime for a significantly
long time that makes the client-server unresponsive
and cause timeouts in clients.
2025-01-30 11:33:21 +01:00
b49cfe96f4 event/Thread: start the thread in the constructor
This is the proper fix for the e309941646 regression; see
commit abc8420697
2025-01-30 10:58:34 +01:00
ae112fe077 Merge branch 'sticker_errors' of https://github.com/jcorporation/MPD 2025-01-30 10:48:18 +01:00
a1cbfa1623 Merge branch 'sticker_set' of https://github.com/jcorporation/MPD 2025-01-30 10:46:23 +01:00
e06d775af5 util/CircularBuffer: add method MoveTo()
This implements wraparound, so AsyncInputStream and ThreadInputStream
can now return all of the buffer contents in one Read() call.
2025-01-29 21:28:28 +01:00
950f5f4d32 input/{async,thread}: move code to ReadFromBuffer() 2025-01-29 21:26:05 +01:00
abc8420697 Main: start IO threads before initializing the rest
This fixes a regression triggered by commit e309941646 -
IORING_SETUP_SINGLE_ISSUER broke because io_uring_setup() was called
fromm the main thread, yet io_uring_submit() in the I/O thread.  This
is because the I/O thread was not yet started when
InitUringInputPlugin() was called, and BlockingCall() was invoked
synchronously in the main thread.  This has always been wrong, but was
never noticed.
2025-01-29 21:25:59 +01:00
e309941646 event/Loop: initialize io_uring with IORING_SETUP_SINGLE_ISSUER
This might give tiny kernel-side optimizations.
2025-01-29 20:29:42 +01:00
ea2ced6b9f event/UringManager: replace with new Uring::Manager class
From https://github.com/CM4all/libcommon - the new class is mostly
identical, and I want to maintain only one of them.
2025-01-29 20:27:13 +01:00
f1d06396a7 client: replace num with a name string
This logs the client address (or the process id and uid for local
connections) in each log line instead of the number.
2025-01-29 20:24:05 +01:00
95c0e2505c client/New: pass SocketPeerCredentials to client_new() 2025-01-29 19:36:47 +01:00
7adda0aa66 event/ServerSocket: move GetPeerCredentials() call to ClientListener::OnAccept() 2025-01-29 19:32:53 +01:00
a0825e6ce0 net/PeerCredentials: add getpeereid() support 2025-01-29 19:28:09 +01:00
c7621ec0e4 net/PeerCredentials: wrapper for struct ucred 2025-01-29 19:28:03 +01:00
2c7ca16c4e lib/fmt/ToBuffer: add constexpr 2025-01-29 18:12:08 +01:00
ad8c2577c4 util/PackedBigEndian: add class PackedSignedBE16 2025-01-29 18:11:47 +01:00
7c9a460786 io/uring/Ring: add method SetMaxWorkers() 2025-01-29 18:10:59 +01:00
c644b7616a io/uring/Ring: add ctor wrapping io_uring_queue_init_params() 2025-01-29 18:10:20 +01:00
badf7101e2 io/uring/Ring: use if with initializer 2025-01-29 18:10:04 +01:00
6fb91e661c io/uring/Queue: DispatchCompletions() returns bool 2025-01-29 18:09:57 +01:00
ed819a05e3 io/uring/Ring: add SubmitAndGetEvents() 2025-01-29 18:09:52 +01:00
2e3a51a5da io/uring/Close: use IOSQE_CQE_SKIP_SUCCESS
We don't want to get any completion events for "close".  It's
fire-and-forget.
2025-01-29 18:09:29 +01:00
e682940c54 event/PipeEvent: add GetScheduledFlags(), [GS]etReadyFlags() 2025-01-29 18:09:10 +01:00
fa375cbaeb event/uring/Manager: un-inline the ctor 2025-01-29 18:09:06 +01:00
3f638bfa03 io/uring/Operation: add method GetUringData() 2025-01-29 18:07:55 +01:00
0ba0c64093 event/uring/Manager: add flags parameter 2025-01-29 18:07:46 +01:00
5e107c33d9 event/DeferEvent: add ScheduleNext() 2025-01-29 18:05:50 +01:00
4bb379a218 event/ServerSocket: use SocketDescriptor::GetPeerCredentials() 2025-01-29 17:56:26 +01:00
3710b54d43 event/ServerSocket: pass SocketDescriptor to get_remote_uid() 2025-01-29 17:56:26 +01:00
70f1f9cff8 subprojects: update gtest to 1.15.2 2025-01-29 17:41:24 +01:00
9787d39c3f subprojects: update expat to 2.6.4 2025-01-29 17:41:11 +01:00
54527068d5 .github/workflows/build.yml: fix matrix name
Regression by commit ab011adf77
2025-01-29 17:35:33 +01:00
0186f73c7a client/Process: let libfmt quote the command string 2025-01-29 17:32:42 +01:00
gd
88594c81d6 Logging: added seconds to log time string.
Time was only in minutes before.
Seconds is more useful in analyzing the log for example
with issues of timeouts, and reponse times.
2025-01-29 17:31:21 +01:00
f6bd49ba61 Merge branch 'tag-compare' of https://github.com/geneticdrift/MPD 2025-01-29 17:21:54 +01:00
a404e5754e Merge tag 'v0.23.17'
release v0.23.17
2025-01-29 17:20:02 +01:00
b080ca8627 release v0.23.17 2025-01-29 17:11:53 +01:00
0e8cd3b961 client/Process: explicitly disallow "idle" and "noidle" in command lists
These commands cannot possibly work with command lists because command
lists are supposed to be atomic, but suspended command execution
conflicts with that.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2167
2025-01-29 17:08:53 +01:00
8fcb6e148f decoder/list: probe "ffmpeg" before "sndfile" and "audiofile"
For FFmpeg's DTS-WAV support, see code comment.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2158
2025-01-29 15:42:54 +01:00
gd
ce9ee38304 decoder/Bridge: DecoderBridge::UpdateStreamTag - return false if stream tag not changed.
Some streams send the same tags frequently, causeing unnecessary update
events.
2025-01-29 16:02:20 +02:00
gd
f9d47502d8 player/Thread: update song tag from remote stream only if changed.
Some streams send the same tags frequently, causing unnecessary player queue update events.
2025-01-29 16:00:37 +02:00
gd
f15014b6af tag/Item: made TagItem constructor private and friend TagPoolItem
To only allow construction as part of TagPoolItem with its special var size allocator in TagPoolItem::Create.
2025-01-29 16:00:37 +02:00
gd
2a9c3a2e50 tag/Tag: added operator==(Tag&) 2025-01-29 16:00:37 +02:00
gd
3e9c2cce71 tag/Item: added operator== to TagItem 2025-01-29 16:00:37 +02:00
gd
93bf99f639 util/DereferenceIterator, TerminatedArray: added operator-(const IteratorType&) to DereferenceIterator and TerminatedArray::iterator
It is required by std::distance and some std algos.
2025-01-29 16:00:20 +02:00
c0a9434f34 command/file: "albumart" tries to send larger chunks if available
If we only receive very little data from the InputStream, try a second
Read() call to get more data.  This works around tiny reads at input
buffer boundaries with the io_uring input plugin.  These tiny reads
are inefficient, and we can afford to wait one more low-level I/O
iteration to finish (but not more).

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2186
2025-01-29 13:07:05 +01:00
d7212624b0 input/{async,thread}: clear the CircularBuffer when it becomes empty
First step towards fixing https://github.com/MusicPlayerDaemon/MPD/issues/2186
2025-01-29 13:05:24 +01:00
70a0a781c8 input/async: move the IsEOF() check to a separate block 2025-01-29 12:59:04 +01:00
ab011adf77 meson.build: require GCC 12 or clang 14
GCC 10 doesn't have std::make_unique_for_overwrite(), so let's drop it.
2025-01-29 12:24:48 +01:00
8ea3f86f43 Revert "meson.build: disable -Wsuggest-override with GCC 8"
This reverts commit 56c0733b42.  GCC 8
is no longer supported.
2025-01-29 12:22:11 +01:00
bd78307940 input/{async,thread}: add an additional Cond field
This eliminates the ScopeExchangeInputStreamHandler kludge.
2025-01-29 12:14:42 +01:00
3cc7b7dbf9 Merge branch 'v0.23.x' 2025-01-29 12:09:18 +01:00
57e7fb3f62 tag/Id3Load, ...: use std::make_unique_for_overwrite()
Don't zero-initialize the buffers.  This removes some useless
overhead.
2025-01-29 12:01:27 +01:00
687475cf3c db/update/InotifyUpdate: handle IN_CREATE without IN_ISDIR
A new symlink causes `IN_CREATE`.  Usually, we catch `IN_CREATE` only with
IN_ISDIR to watch the new directory, but otherwise `IN_CREATE` is not
handled.  Regular files are "created" but they have usable content
only with `IN_CLOSE_WRITE`.  Yet symlinks have only `IN_CREATE` and
they are immediately usable.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2192
2025-01-29 09:41:08 +01:00
c48dbd5dd4 lib/nfs/meson.build: reject libnfs 6
libnfs version 6 has major API changes and MPD 0.23 has never been
adapted to these.  This additional configure-time check fixes
potential compile-time failures.
2025-01-29 09:04:55 +01:00
37049aab36 lib/nfs/Connection: remove EnableCloseOnExec() call
SOCK_CLOEXEC has been added to libnfs version 2, and since we require
at least version 4, we can safely remove this call.
2025-01-29 09:02:05 +01:00
18495fbb4e lib/nfs/meson.build: require libnfs 4.0
All Linux distributions have at least version 4, and thus I cannot
test with older versions.
2025-01-29 09:00:37 +01:00
cdcee16738 client/File: improve error message
Users are confused by "Access denied".  Let's write an error message
that is more clear.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2184
2025-01-29 08:28:30 +01:00
83c2d9c964 test/meson.build: add another missing dependency on libevent.a
Necessary for including Client.hxx.
2025-01-28 19:52:25 +01:00
074a041760 test/meson.build: add missing dependencies on libevent.a 2025-01-28 19:47:36 +01:00
083d39ea80 decoder/plugins/meson.build: add missing dependency to libid3tag 2025-01-28 19:38:50 +01:00
a5da7fd51a Merge branch 'v0.23.x' 2025-01-28 19:33:19 +01:00
cf9a2eb508 .github/workflows/build.yml: disable yajl on macOS
This yajl on Homebrew comes with broken headers:

 /opt/homebrew/Cellar/yajl/2.1.0/include/yajl/yajl_parse.h:22:10: fatal error: 'yajl/yajl_common.h' file not found
 #include <yajl/yajl_common.h>
          ^~~~~~~~~~~~~~~~~~~~
2025-01-28 19:31:35 +01:00
0aeda01ba6 lib/yajl: drop "yajl/" prefix from #include paths
According to the yajl API documentation, #include lines should have
the "yajl/" path prefix, but the actual pkg-config file contains:

 includedir=${dollar}{prefix}/include/yajl

.. which already contains this directory name, and thus the "yajl/"
prefix cannot work.  Unfortunately, the yajl project hasn't been
maintained for nearly 10 years, and there's little chance this bug
will ever be fixed.
2025-01-28 19:27:46 +01:00
3798d11a8d .github/workflows/build.yml: disable NFS support
Homebrew comes with libnfs 6 which is not supported by MPD 0.23.
2025-01-28 19:23:36 +01:00
fab03f800a subprojects: remove libmicrohttpd
This one will be pulled in by libnpupnp automatically.  No need to
have it here.
2025-01-28 19:17:06 +01:00
5b5b101c56 subprojects: add id3tag 2025-01-28 19:15:43 +01:00
7770accee0 python/build/libs.py: remove libmad (unused) 2025-01-28 19:14:03 +01:00
eb3cd7bed3 subprojects: add lame 2025-01-28 19:13:59 +01:00
56cc2f4c65 subprojects: add libmpdclient wrap 2025-01-28 19:13:46 +01:00
9723af3f35 subprojects: add openssl 2025-01-28 19:13:45 +01:00
dcf3cf4216 subprojects: add ogg, flac, opus 2025-01-28 19:13:19 +01:00
578c94081f subprojects: add curl 2025-01-28 19:12:57 +01:00
efa8304d2d subprojects/.gitignore: sort 2025-01-28 19:12:42 +01:00
2752f67877 lib/nfs/meson.build: add missing dependency on libevent.a 2025-01-28 19:05:09 +01:00
f55e0df614 lib/curl/meson.build: add missing internal dependency on libevent.a 2025-01-28 18:52:37 +01:00
177ffde90f Merge branch 'v0.23.x' 2025-01-28 18:45:02 +01:00
0d1fb9a02c meson.build: build libnpupnp and libmicrohttpd statically as submodules 2025-01-28 18:43:23 +01:00
a0a39ae828 .github/workflows/build.yml: update actions/checkout to v4 2025-01-28 18:39:17 +01:00
e57c60e3d8 .github/workflows/build.yml: update hendrikmuhs/ccache-action to v1.2 2025-01-28 18:38:59 +01:00
53090e3745 .github/workflows/build.yml: update actions/setup-python to v5 2025-01-28 18:37:06 +01:00
93eb3da48a subprojects: add liburing 2025-01-28 18:35:21 +01:00
75a3d9340e python/build/libs.py: update FFmpeg to 7.1 2025-01-28 18:34:29 +01:00
9445ea1565 subprojects: add libnpupnp 2025-01-28 18:34:29 +01:00
a5a26d304b subprojects: update sqlite3 to 3.48.0-1 2025-01-28 18:34:29 +01:00
1d8d298a22 subprojects: update fmt to 11.1.1-2 2025-01-28 18:34:28 +01:00
508bfbe334 pipewire/meson.build: add "include_type:system"
This suppresses a compiler warning due to sloppy code in PipeWire:

 /usr/include/spa-0.2/spa/utils/json-core.h:440:29: error: implicit conversion increases floating-point precision: 'float' to 'double' [-Werror,-Wdouble-promotion]
   440 |         return spa_dtoa(str, size, val);
       |                ~~~~~~~~            ^~~
2025-01-28 18:34:12 +01:00
1385212572 io/uring/meson.build: detect liburing with include_type=system
This avoids breakages due to `-Wgnu-anonymous-struct`.
2025-01-28 18:34:07 +01:00
8dcd6ea2b4 increment version number to 0.23.17 2025-01-28 18:13:07 +01:00
75d0914373 Merge branch 'fix-handle-status' of https://github.com/geneticdrift/MPD 2025-01-28 06:18:19 +01:00
35dc1fc589 io/UniqueFileDescriptor: use AdoptTag in the constructors that adopt ownership 2025-01-23 16:57:39 +01:00
765a6a2f20 net/UniqueSocketDescriptor: use AdoptTag in the constructors that adopt ownership
This makes it a little bit harder to use the ownershop-adopting
constructors accidently.
2025-01-23 16:56:57 +01:00
131263cbe3 util/TagStructs: add struct AdoptTag 2025-01-23 16:56:00 +01:00
936611b47c util/ShallowCopy: rename header to TagStructs.hxx
This new header will be a collection of more structs like ShallowCopy.
2025-01-23 16:55:51 +01:00
gd
266eb393eb fix: output of command status broken by a misplaced comma in the format arguments 2025-01-21 14:03:41 +02:00
194ecd69e0 lib/fmt: remove even more now-broken uses of FMT_STRING
MPD stopped building since fmt 11.1.0; see
<https://github.com/fmtlib/fmt/issues/4304>. The first commit
fixing this was 9db7144, followed by 5de0909 (both on the
unstable branch).

This commit removes what the author believes to be the remaining
uses in the MPD codebase.
2025-01-20 19:54:41 -08:00
b24b3c1054 Merge remote-tracking branch 'upstream/v0.23.x' 2025-01-20 09:44:07 -08:00
5de0909ae5 lib/fmt: remove the rest of the broken use of FMT_STRING
Fixes: 9db7144d0f
Signed-off-by: Alfred Wingate <parona@protonmail.com>
2025-01-18 03:29:14 +02:00
da6efd6361 plugins/meson.build: revert unintentional static link change
Minor revert of 9db7144d0f
- no change was to be done to meson.build.
2025-01-13 22:39:12 +00:00
9db7144d0f lib/fmt: drop use of FMT_STRING
When compiling with libfmt-11.1.0 and newer the following compile errors occur:

In file included from ../src/decoder/DecoderPrint.cxx:23:
../src/client/Response.hxx: In instantiation of 'bool Response::Fmt(const S&, Args&& ...) [with S = decoder_plugin_print(Response&, const DecoderPlugin&)::<lambda()>::FMT_COMPILE_STRING; Args = {const char* const&}]':
../src/decoder/DecoderPrint.cxx:38:7:   required from here
   38 |         r.Fmt(FMT_STRING("plugin: {}\n"), plugin.name);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/client/Response.hxx:86:28: error: cannot convert 'const decoder_plugin_print(Response&, const DecoderPlugin&)::<lambda()>::FMT_COMPILE_STRING' to 'fmt::v11::string_view' {aka 'fmt::v11::basic_string_view<char>'}
   86 |                 return VFmt(format_str,
      |                        ~~~~^~~~~~~~~~~~
   87 |                             fmt::make_format_args(args...));
      |                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/client/Response.hxx:81:36: note: initializing argument 1 of 'bool Response::VFmt(fmt::v11::string_view, fmt::v11::format_args)'
   81 |         bool VFmt(fmt::string_view format_str, fmt::format_args args) noexcept;
      |                   ~~~~~~~~~~~~~~~~~^~~~~~~~~~
../src/client/Response.hxx: In instantiation of 'bool Response::Fmt(const S&, Args&& ...) [with S = decoder_plugin_print(Response&, const DecoderPlugin&)::<lambda()>::FMT_COMPILE_STRING; Args = {const char* const&}]':

The error is due to the use of FMT_STRING. The libfmt team shared the following:

    The correct way of using FMT_STRING is to wrap a format string when passing to a
    function with compile-time checks (i.e. that takes format_string) as documented
    in https://fmt.dev/11.1/api/#legacy-compile-time-checks.

    Noting that FMT_STRING is a legacy API and has been superseded by consteval-based
    API starting from version 8: https://github.com/fmtlib/fmt/releases/tag/8.0.0. It
    looks like MPD is trying to emulate {fmt}'s old way of implementing compile-time
    checks which was never properly documented because it was basically a hack. So the
    correct fix is to switch to format_string and, possibly, remove usage of FMT_STRING.

    The old way of doing compile-time checks (fmt::make_args_checked) was documented
    in https://fmt.dev/7.1/api.html#argument-lists but it looks like MPD is not using
    that API so the problematic uses of FMT_STRING have no effect and can just be removed.

The FMT_STRING has been removed in this change based on the fmt-7.1 API and now MPD is
successfully compile against the current libfmt-11.1.0 which highlighted the issue that
had been present in the codebase as it is now triggering the error, is legacy and was
not using the API for which FMT_STRING was aligned with.
2025-01-13 06:17:01 +00:00
bd36b5e310 Response with error for sticker set,inc,dec and add missing asserts 2024-12-12 19:40:06 +01:00
015870ac71 Replace STICKER_SQL_INSERT and STICKER_SQL_UPDATE with STICKER_SQL_SET that lets handle sqlite insertion or update of the sticker value. 2024-12-12 19:15:22 +01:00
b1677bf79c Merge branch 'sticker_inc_dec' of https://github.com/jcorporation/MPD 2024-12-12 08:38:58 +01:00
1078c1c1bf Add sticker sub-commands inc and dec
Let sqlite do the work for incrementing or decrementing a sticker value.
This sub-commands are usefull to track playcounts with sticker values and
saves us one roundtrip.
2024-12-11 21:41:24 +01:00
9a8579d956 event/ServerSocket: do not close all listeners before rethrowing
If binding one address fails, we don't need to close all listeners.
For fatal errors, this will be done automatically and implicitly; and
for non-fatal errors (e.g. binding to the default port failed, but
there is an XDG listener), this closes the good listeners which are
supposed to be used.

Closes https://github.com/MusicPlayerDaemon/MPD/pull/2157
2024-12-04 14:25:42 +01:00
b6e187efd8 Merge tag 'v0.23.16'
release v0.23.16
2024-12-03 13:01:15 +01:00
30d2a31473 command/sticker: remove unreachable code 2024-12-03 12:32:33 +01:00
9a7a8ec137 io: always pass O_NONBLOCK to open()
Opening a FIFO may block indefinitely (until a writer connects).  This
is dangerous because it may be a DoS vulnerability in many programs
that do not expect open() to block.

This obsoletes the method FileDescriptor::OpenNonBlocking() which
wasn't used anyway.
2024-12-03 12:28:17 +01:00
88fa68f030 net/SocketDescriptor: add GetPeerPidfd() 2024-12-03 12:27:20 +01:00
78e643150f output/Source: fix Close()
Close the filter before cancelling when closing a source.
Fixes 
2024-11-19 10:59:35 +00:00
eb1463fd7c test/util/TestIntrusiveTreeSet: add constant_time_size test 2024-11-13 10:44:28 +01:00
6dce8dcaa5 io/FileDescriptor: add readv()/writev() wrappers 2024-11-13 10:44:03 +01:00
fc4a579d83 io/FileDescriptor: remove Read()/Write() with void pointers
Obsolete and unsafe.
2024-11-13 10:43:34 +01:00
263b9916c2 unix/PidFile: pass std::span to FileDescriptor::Read() 2024-11-13 10:43:33 +01:00
16604997d6 system/{Event,Signal}FD: pass std::span to FileDescriptor::Read() 2024-11-13 10:43:08 +01:00
77226bc0d8 test/ReadFrames: pass std::span to FileDescriptor::Read() 2024-11-13 10:42:35 +01:00
7a6672b7ed util/IntrusiveTreeSet: update the counter, fixing constant_time_size 2024-11-13 10:36:57 +01:00
8db14c9cb3 Instance: add method FindOutput()
Move code from handle_moveoutput().
2024-11-11 19:08:45 +01:00
370df37596 io/uring/Ring: add more API documentation 2024-11-11 19:04:24 +01:00
84e3501084 io/uring/Queue: remove redundant include 2024-11-11 19:04:21 +01:00
a7d41a99a1 util/ForeignFifoBuffer: pass std::span to constructor 2024-11-11 19:03:31 +01:00
c9c5e84119 util/ForeignFifoBuffer: store buffer as std::span 2024-11-11 19:02:58 +01:00
8a3b48754e util/ForeignFifoBuffer: use Read() in MoveBuffer() and Shift() 2024-11-11 19:02:43 +01:00
849c4012c0 filter/Filter: add method ReadMore()
This allows FilterPCM() to return more data, which some
implementations may need to do (e.g. FFmpeg).
2024-11-08 19:31:16 +01:00
d8bb833ba3 output/Source: convert runtime check to assert()
Flush() may only be called if the source is open.
2024-11-08 19:09:31 +01:00
4d8a2ea688 output/Source: add assert(filter) 2024-11-08 18:50:48 +01:00
a7a61e9e41 output/Source: add inline 2024-11-08 18:34:22 +01:00
415cf096e9 output/Thread: add another inline 2024-11-08 18:24:48 +01:00
7774c3369e filter/two: check empty() instead of data()==nullptr
See bcab29d53a
2024-11-05 22:37:36 +01:00
bcab29d53a filter/Filter: Flush() returns empty span, not nullptr 2024-11-05 13:19:25 +01:00
d6195025fb filter/Filter: clarify Flush() documentation 2024-11-05 13:11:25 +01:00
d7ae512b5e filter/Filter: clarify that the FilterPCM() return value may be empty
And adjust TwoFilter accordingly.
2024-11-05 12:35:10 +01:00
b7b4c6b4ea filter/Filter: Flush() also invalidates the returned buffer
Just API documentation.
2024-11-05 12:35:09 +01:00
f59f17013d MusicChunk: add method ReadData() 2024-11-05 12:34:35 +01:00
4beedec3ad MusicChunk: add missing include 2024-11-05 12:31:30 +01:00
950888d161 output/Source: fix indent 2024-11-05 12:28:41 +01:00
76562fc093 test/run_{filter,output}: use fmt 2024-11-05 11:48:37 +01:00
0676ab7f47 filter/two: use if with initializer 2024-11-02 22:48:02 +01:00
fc5d258890 filter/ffmpeg: fill AVFrame::pts
Some libavfilter plugins don't produce any output if `pts` is never
set, e.g. the `lowpass` plugin.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2114
2024-11-02 22:24:53 +01:00
7dce7ad32d Merge branch 'tagtypes_reset' of https://github.com/jcorporation/MPD 2024-11-02 20:58:06 +01:00
fa29693550 filter/ffmpeg: implement method Flush() 2024-11-02 20:55:04 +01:00
2c881c63ba doc/plugins.rst: fix spelling 2024-11-02 19:37:13 +00:00
fd7d251358 Add "reset" subcommand to tagtypes.
This subcommand combines "clear" and "enable" in one command.
2024-11-01 18:07:06 +01:00
acb9ee9792 filter/ffmpeg: move code to ReadOutput() 2024-10-30 22:49:20 +01:00
3d99f1d8a6 filter/ffmpeg: use if with initializer 2024-10-30 22:47:21 +01:00
2ef36af68d test/run_filter: add command line parser 2024-10-30 22:17:42 +01:00
d7b4634e5e io/FileLineReader: add missing include 2024-10-30 21:47:37 +01:00
2bc57c38d2 meson.build: set cpp_std=c++20
Meson supports this since version 0.57.0.
2024-10-30 21:37:49 +01:00
744308bfff python/build/libs.py: update FFmpeg to 7.1 2024-10-30 21:31:17 +01:00
7db93fb20b subprojects: update sqlite3 to 3.47.0-1 2024-10-30 21:29:57 +01:00
95db2db736 subprojects: update curl to 8.10.1-1 2024-10-30 21:29:47 +01:00
f807345022 event/Loop: use std::chrono::ceil()
Thanks to C++17, we don't need our custom implementation anymore.
2024-10-30 21:29:16 +01:00
b745d1f226 util/StringCompare: add constexpr 2024-10-30 21:29:16 +01:00
52e2130d51 util/StringCompare: simplify StringIsEqual() using operator== 2024-10-30 21:28:15 +01:00
1930ed16cb Merge branch 'icu76-support' of https://github.com/cho-m/MPD 2024-10-27 15:22:04 +01:00
1a063fee7e meson.build: support building with ICU 76
ICU 76 decided to reduce overlinking[^1] thus `icu-i18n` will no longer
add `icu-uc` when linking to shared libraries. This results in failure:
```
src/lib/icu/libicu.a.p/Converter.cxx.o: undefined reference to symbol 'ucnv_fromUnicode_76'
```

[^1]: 199bc82702
2024-10-27 09:57:22 -04:00
51e0fefda7 Fix order of commands 2024-10-26 11:32:36 +02:00
449f8af7d0 Merge branch 'protocol_features' of https://github.com/jcorporation/MPD 2024-10-26 08:18:56 +02:00
38b46e680a Merge branch 'stickernames-types' of https://github.com/jcorporation/MPD 2024-10-26 08:16:53 +02:00
17d0cd0abd Merge branch 'queue_loaded_playlist' of https://github.com/jcorporation/MPD 2024-10-26 08:15:23 +02:00
98bc63251e Merge branch 'searchplaylist_pos' of https://github.com/jcorporation/MPD 2024-10-26 08:14:31 +02:00
030bac441f Merge branch 'playlistlength_fix' of https://github.com/jcorporation/MPD 2024-10-26 08:13:14 +02:00
f82a385be2 Merge branch 'tagtypes_available' of https://github.com/jcorporation/MPD 2024-10-26 08:10:07 +02:00
052719c0e4 Fix integer overflow calculating length of very large playlists 2024-10-20 12:12:50 +02:00
bfbff31860 Store last loaded playlist
Stores the last loaded playlist uri in the queue struct.
Last loaded playlist is set on load command and cleared with the clear command.
The last loaded playlist is printed in the status command and saved / restored from the partition state file.

Resolves issue 
2024-10-20 12:03:31 +02:00
b1067333dc Print positions in the search playlist functions. 2024-10-20 11:55:52 +02:00
35bdf74952 Mention contains and starts_with for "sticker find" 2024-09-28 22:43:20 +02:00
23c2bba483 This commit adds a new protocol command to toggle protocol features
for a client connection. It works like the tag_mask and the associated
tagtypes command.

New commands:

- protocol
  Shows enabled protocol features.

- protocol available
  Show all available protocol features.

- protocol enable {feature...}
  Enables protocol features.

- protocol disable {feature...}
  Disables protocol features.

- protocol all
  Enables all available protocol features.

- protocol clear
  Disables all protocol features.

This commit adds also the first protocol feature.

hide_playlists_in_root
  Disables the listing of playlists in the root folder
  for the lsinfo command.
2024-09-28 22:41:35 +02:00
25e8ce2d37 New command tagtypes available
Shows the list of tag types configured by the ``metadata_to_use`` setting.
2024-09-28 22:40:29 +02:00
124c0e66ee subprojects: update libnpupnp to 6.2.0-1, libmicrohttpd to 0.9.77-3 2024-09-27 08:53:01 +02:00
202bb4f90f subprojects: update fmt to 11.0.2-1 2024-09-27 08:52:22 +02:00
5ee42ada67 subprojects: update curl to 8.10.0-1 2024-09-27 08:52:10 +02:00
752c6c1f03 lib/fmt/ExceptionFormatter: move the exception_ptr 2024-09-27 08:48:30 +02:00
def2221dfd Merge branch 'searchplaylist_syntax' of https://github.com/jcorporation/MPD 2024-09-27 08:47:02 +02:00
9ff8e02e54 net/Resolver: use StringIsEqual() 2024-09-04 17:26:45 +02:00
32dd9704ce util/DeleteDisposer: add const and noexcept 2024-09-04 17:24:42 +02:00
523519182a util/IntrusiveHashSet: add concept checks 2024-09-04 17:24:24 +02:00
3f718e8924 Change the semantic of the searchplaylist protocol command
Old: searchplaylist {NAME} {FILTER} [{START:END}]
New: searchplaylist {NAME} {FILTER} [window {START:END}]

This is more similar to the other search commands and we can reuse search specific functions in libmpdclient.
2024-08-30 21:06:50 +02:00
26c4211cd4 New command stickernamestypes
Lists sticker names with their types and optionally filters by type
2024-08-30 20:14:55 +02:00
a3a07280e8 Merge branch 'mpd-2100-nested-and' of https://github.com/m7a/mpd 2024-08-30 12:57:20 +02:00
ed755f04e9 lib/fmt/meson.build: suppress -Warray-bounds with GCC 14
The bug is still present in GCC 14.
2024-08-30 12:48:41 +02:00
2809db8b40 Merge branch 'searchplaylist' of https://github.com/jcorporation/MPD 2024-08-30 12:47:24 +02:00
c866199d4c net/SocketError: cast to socket_error_t to fix -Wsign-compare
Only relevant on Windows where socket_error_t is a `DWORD` (unsigned).
2024-08-30 12:45:10 +02:00
39937be2e1 Merge branch 'stickertypes' of https://github.com/jcorporation/MPD 2024-08-30 12:43:54 +02:00
d207c144d6 lib/curl/Multi: remove the Wait() overload with "int" timeout
Enforce type-safety.
2024-08-30 12:30:18 +02:00
435f1eb6cc lib/curl/Multi: remove default timeout value
-1 is an illegal value and leads to CURLM_BAD_FUNCTION_ARGUMENT.  Our
API shouldn't imply this value.
2024-08-30 12:30:15 +02:00
c7b80b0828 io/FileDescriptor: add method WriteAt() 2024-08-30 12:29:32 +02:00
59199b5620 io/FileDescriptor: pass std::span to ReadAt() 2024-08-30 12:29:27 +02:00
ebfc83dac5 io/FileDescriptor: add method SetPipeCapacity() 2024-08-30 12:28:51 +02:00
f535ccf9bf net/UniqueSocketDescriptor: add UniqueFileDescriptor constructor 2024-08-30 12:28:19 +02:00
75eb2c257c net/SocketError: add IsSocketError() overload with socket_error_t 2024-08-30 12:27:19 +02:00
314667259e net/SocketDescriptor: add Duplicate() method
The the Duplicate() method we inherited from class FileDescriptor
returns a UniqueFileDescriptor, but we really want to return a
UniqueSocketDescriptor.
2024-08-30 12:27:13 +02:00
dbb2b29271 net/IPv6Address: add method GetPortBE() 2024-08-30 12:24:12 +02:00
7f25ede888 net/AddressInfo: add method Cast() 2024-08-30 12:23:45 +02:00
4a2fff019a util/DisposablePointer: suppress -Wuninitialized
I pretend to know what I'm doing :-)
2024-08-30 12:23:45 +02:00
fae5d16d43 subprojects: update curl to 8.9.1-1 2024-08-30 12:23:41 +02:00
7bc2259b35 subprojects: update sqlite3 to 3.46.1-1 2024-08-30 12:23:27 +02:00
f66aed921c python/build/libs: update FFmpeg to 7.0.2 2024-08-30 12:22:37 +02:00
6db4b818e6 song/Filter: Fix spacing error on nested AND
Previously, `AND` expressions were the only filters which used `++s` instead
of `s = StripLeft(s + 1)` making them sensitive to spacing issues. This caused
nested AND expressions (like e.g. `(((A) AND (B)) AND (C))`) to needlessly be
rejected with the following error message: `{find} Word expected` due to the
fact that the inner AND expression would leave the cursor `s` at a space rather
than the beginning of the next word (remainder was ` AND (C))` rather than
`AND (C)`).

This commit fixes this by consistently using `s = StripLeft(s + 1)` instead
of `++s` when parsing AND expressions. Although it is not strictly necessary
to resolve the AND nesting bug, the case of trivial AND expressions (consisting
basically of only superfluous parentheses) is also changed to the new handling.
This should be more robust although I expect that case to be even less common
than the direct nesting of AND expressions.

see 
2024-08-23 21:36:53 +02:00
f94caa96b8 Add command stickertypes
Prints all available stickertypes like tagtypes for tags.
2024-08-14 21:07:14 +02:00
965c466e9b Merge branch 'mpg-duration-fix' of https://github.com/boedy/MPD 2024-08-10 16:54:48 +02:00
731f20111a Override the value for file size in bytes. Useful for getting sensible track length values in feed mode or for HTTP streams.
https://www.mpg123.de/api/group__mpg123__status.shtml#gad0301e80dbc3f48e47e27d39cd328755
2024-08-08 18:43:15 +02:00
d62f7cdc34 New command searchplaylist 2024-08-02 23:46:17 +02:00
f7790430a0 lib/curl/Multi: add SetSocketFunction(), SetTimerFunction() 2024-07-31 10:06:29 +02:00
959826d1d1 input/ffmpeg: offload FFmpeg calls to thread
Prepare for interruptible I/O.
2024-07-30 12:43:05 +02:00
ec30716e01 input/thread: implement size and seek 2024-07-30 12:33:44 +02:00
dc51015c75 input/mms: move MMS_BUFFER_SIZE into the class 2024-07-30 12:33:30 +02:00
72b0eeb7b1 input/mms: invoke Start() in constructor 2024-07-30 12:31:58 +02:00
b050e0132e input/{async,thread}: add an additional Cond field
This eliminates the ScopeExchangeInputStreamHandler kludge.
2024-07-29 23:17:33 +02:00
cf962d94c7 input/thread: remove bogus inline 2024-07-29 23:14:16 +02:00
c29d23b4c3 input/thread: use notify_one() instead of notify_all()
There's only ever one waiter, and notify_one() may be faster than
notify_all().
2024-07-29 23:09:07 +02:00
61e8df913d input/thread: check IsEOF() in IsAvailable() 2024-07-29 23:05:00 +02:00
4a55e3e8bd input/thread: check buffer.empty() in IsEOF() 2024-07-29 23:03:00 +02:00
2e78bd430c input/thread: use pass std::span<std::byte> to ThreadRead() 2024-07-29 22:32:52 +02:00
dbaa72cb40 util/CircularBuffer: use std::span internally 2024-07-29 22:24:54 +02:00
596d2d93dd util/CircularBuffer: use using instead of typedef 2024-07-29 22:21:38 +02:00
10311b3a65 util/CircularBuffer: explicitly forbid the copy operator 2024-07-29 22:20:15 +02:00
332ba42073 util/HugeAllocator: add std::span cast operator 2024-07-29 22:20:12 +02:00
4262d29965 util/HugeAllocator: add constexpr 2024-07-29 22:19:28 +02:00
0899d80ae0 util/CircularBuffer: add noexcept and constexpr 2024-07-29 22:14:59 +02:00
9fe6493fc2 util/CircularBuffer: use inline initializer 2024-07-29 22:13:50 +02:00
902cb8efac input/thread: use std::byte instead of uint8_t 2024-07-29 22:13:50 +02:00
f54210bf68 input/async: move enum definition down 2024-07-29 22:13:42 +02:00
fb151c8662 lib/fmt/meson.build: suppress -Warray-bounds with GCC 13 2024-07-29 22:13:11 +02:00
323517753d lib/fmt/meson.build: remove obsolete clang 14 workaround
Android NDK r27 has clang 18 and I don't feel like supporting clang 14.
2024-07-29 22:11:20 +02:00
5726d9f06a mixer/Memento: include cleanup 2024-07-29 17:04:53 +02:00
0992fab1c8 filter/ReplayGain: include cleanup 2024-07-29 17:04:30 +02:00
b546ddc54c client/Idle: include cleanup 2024-07-29 17:03:59 +02:00
d45b7cc972 IdleFlags: move to procool/ 2024-07-29 17:02:33 +02:00
12eaaef210 output/Thread: allow Delay() to return duration::max()
Eliminate the periodic wakeups while paused in some output plugins.
2024-07-29 16:52:36 +02:00
5b8ef9a62b python/build/__init__.py: add missing file 2024-07-29 16:51:40 +02:00
196258ea13 .github/workflows/build_android.yml: update NDK to r27 2024-07-29 16:38:26 +02:00
0a035f3ce0 output/alsa: add option "close_on_pause"
This allows keeping the ALSA PCM open even if playback is paused.  As
a side effect, this allows using the "always_on" option with ALSA
outputs, because "always_on" pauses the output.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1623
2024-07-29 16:31:09 +02:00
7ab789fbaf doc/user.rst: add clarification to the "always_on" option 2024-07-29 16:30:15 +02:00
9c8f4aaf99 lib/alsa/meson.build: require libasound 1.2 or later
This allows us to drop the 1.1.4 snd_pcm_drain() bug workaround (added
by commit f85d4d28d1).
2024-07-29 15:42:46 +02:00
3bef4f839a output/alsa: fix coding style 2024-07-29 15:40:52 +02:00
1dfda3a5e1 output/alsa: reorder fields to improve packing 2024-07-29 15:38:02 +02:00
9d9c4045e2 output/alsa: move redundant code to UnregisterSockets() 2024-07-29 15:28:58 +02:00
d466deedad output/alsa: fix lambda indent 2024-07-29 15:28:27 +02:00
bbbbf5f4bd event/MultiSocketMonitor: reschedule epoll/EPERM workaround forever
Fixes a regression by commit 3558317dc9 which caused the ALSA null
plugin to cease to work because the workaround timer was never rescheduled.
2024-07-25 20:16:53 +02:00
f030b22bec player/thread: wait for the first chunk in CheckCrossFade()
This fixes MixRamp problems which occur because CheckCrossFade() is
called before the decoder has parsed MixRamp tags after
DecoderClient::Ready().

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2084
2024-07-25 20:07:52 +02:00
a693052f2c Merge branch 'feat/showmovement' of https://github.com/mayanez/MPD 2024-07-25 14:01:19 +02:00
e3809bd4f0 feat: Add ShowMovement Tag
This commit adds the `SHOWMOVEMENT` [tag](https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html#show-work-movement-4). Historically, this tag originates from iTunes' MP4, but has since become widely used. It is created by Picard's Classical music [plugins](https://picard-docs.musicbrainz.org/en/variables/variables_classical.html) (such as "Classical Extras" or "Work & Movement").

The reasoning behind this tag is to display Work & Movement titles without redundant information and in a more uniform way. Moreover, it additionally serves as an implicit marker denoting classical music tracks (genre tags aren't sufficient).

If the client so chooses to support this tag, they can display `Work` and `Movement` instead of the track title allowing for cleaner display. Other clients can continue to display the `%title%` as before without any fuss.
2024-07-23 21:09:31 -07:00
41cc695848 Instance: fix io/rtio thread mixup
Fixes regression by commit 43d633f560
2024-07-23 15:12:30 +02:00
3558317dc9 event/MultiSocketMonitor: remove force-refresh on every iteration
libasound guarantees that the file descriptors never change for a
"prepared" PCM device, thus we can omit this defensive kludge.
2024-07-23 15:08:55 +02:00
18cb34825d input/alsa: use libfmt instead of std::string concatenation 2024-07-23 15:04:49 +02:00
4c4a3c8664 event/TimerList: use FineTimerEvent::GetDue()
Avoid accessing the private field from an inner class of the friend
class, because some compilers apparently don't like it (Apple clang).
2024-07-23 13:38:05 +02:00
b4374ddb35 python/build/libs.py: update libopenmpt to 0.7.9 2024-07-23 13:08:04 +02:00
d24e7763f6 net/AddressInfo: remove unnecessary operator!=()
The compiler must generate this implicitly from operator==().
2024-07-23 13:05:19 +02:00
49ad4e9f3c io/FileDescriptor: remove unnecessary operator!=()
The compiler must generate this implicitly from operator==().
2024-07-23 13:05:02 +02:00
ea96b321dc net/SocketAdddress: remove unnecessary operator!=()
The compiler must generate this implicitly from operator==().
2024-07-23 13:04:48 +02:00
bc758cece0 util/StringPointer: remove unnecessary operator!=()
The compiler must generate this implicitly from operator==().
2024-07-23 13:04:37 +02:00
0e4885c1fa util/IterableSplitString: remove unnecessary operator!=()
The compiler must generate this implicitly from operator==().
2024-07-23 13:04:30 +02:00
9944c97203 util/AllocatedString: remove unnecessary operator!=()
The compiler must generate this implicitly from operator==().
2024-07-23 13:04:20 +02:00
58a5550439 util/AllocatedArray: remove unnecessary operator!=()
The compiler must generate this implicitly from operator==().
2024-07-23 13:04:10 +02:00
8e42467bd2 decoder/mpg123: relax mpg123_length() check in Scan()
Do not fail the Scan() function completely if libmpg123 cannot
determine the duration.
2024-07-12 16:11:08 +02:00
e00e7802c8 decoder/mpg123: report unknown duration if mpg123_length()<0
Closes https://github.com/MusicPlayerDaemon/MPD/issues/2058
2024-07-12 16:09:35 +02:00
55d0bbade2 decoder/mpg123: move code to GetDuration() 2024-07-12 16:08:11 +02:00
de9f0dc910 playlist/Plugin: convert _init() and _finish() to methods 2024-07-12 16:00:42 +02:00
cf5970a6e1 output/Registry: replace output_plugins_for_each() with a container class 2024-07-12 15:55:01 +02:00
29747a213f playlist/Registry: replace playlist_plugins_for_each() with a container class 2024-07-12 15:52:05 +02:00
c64b4838dc encoder/List: replace encoder_plugins_for_each() with a container class 2024-07-12 14:59:18 +02:00
040c4a8560 archive/ArchiveList: replace archive_plugins_for_each() with a container class 2024-07-12 09:58:19 +02:00
90dfa437e0 lib/alsa/NonBlock: use a persistent pollfd array
This implements the semantic API change introduced by commit
cd04da2bcf
2024-07-11 21:47:15 +02:00
4486b2eded lib/alsa/NonBlock: add common base class 2024-07-11 21:38:45 +02:00
3db8a4f41b lib/alsa/NonBlock: embed in "namespace Alsa" 2024-07-11 21:33:03 +02:00
9704cf3dcb lib/alsa/NonBlock: fix lambda indent 2024-07-11 21:12:18 +02:00
9aa6b03ba8 event/MultiSocketMonitor: pass std::span to ReplaceSocketList() 2024-07-11 21:09:27 +02:00
45f92f0ef0 event/MultiSocketMonitor: fix lambda indent 2024-07-11 21:06:33 +02:00
23a3278b4e event/MultiSocketMonitor: make ctor protected and explicit 2024-07-11 21:05:11 +02:00
951f916440 mixer/alsa: add noexcept 2024-07-11 21:03:41 +02:00
fb87e19bae input/Registry: replace the input_plugins_for_each macros with a container class 2024-07-11 20:52:44 +02:00
49edb16de0 decoder/Thread: add enum DecodeResult, log better diagnostics
Closes https://github.com/MusicPlayerDaemon/MPD/issues/2076
2024-07-11 16:47:43 +02:00
8671896e4c decoder/Thread: throw StopDecoder if command==STOP in decoder_run_stream()
Everybody else is doing that, so let's do the same and not pretend
playback was successful.
2024-07-11 16:28:57 +02:00
c2470ebd9c decoder/List: eliminate decoder_plugins_try()
Migrate callers to GetEnabledDecoderPlugins().  By not using lambdas,
we can switch to enums as return value for better diagnostics.
2024-07-11 16:15:38 +02:00
a27fb71c4c decoder/List: add iterable container for decoder plugins 2024-07-11 15:30:31 +02:00
f6a687dc2b util/FilteredContainer: new class 2024-07-11 15:30:30 +02:00
9210705598 util/TerminatedArray: new class 2024-07-11 15:30:30 +02:00
3d995bba5f util/DereferenceIterator: add class DereferenceContainerAdapter 2024-07-11 14:55:35 +02:00
c77f5095d6 util/DereferenceIterator: allow comparing with sentinel end iterators 2024-07-11 14:55:35 +02:00
3701378449 util/DereferenceIterator: fix operator- and operator+ return types 2024-07-11 14:29:10 +02:00
cb9f3c1a5b util/DereferenceIterator: optimize and simplify increment/decrement operators 2024-07-11 14:27:23 +02:00
fe66cde616 util/DereferenceIterator: add constexpr 2024-07-10 20:13:24 +02:00
0cc9ef0aee util/DereferenceIterator: remove unnecessary operator!=()
The compiler must generate this implicitly from operator==().
2024-07-10 20:13:19 +02:00
68a424d9e1 util/DereferenceIterator: add missing const 2024-07-10 20:11:55 +02:00
13576b8a2e lib/curl/Easy: use pass std::chrono::duration to SetTimeout() 2024-07-10 16:58:16 +02:00
7c21d57953 config/Block: add method GetDuration() 2024-07-10 16:58:16 +02:00
1e9e182a32 config/Data: merge the two duration parser methods, pass minimum value 2024-07-10 16:49:18 +02:00
3733bc57b7 config/{Block,Data,Param}: add concept checks to With() 2024-07-10 16:38:08 +02:00
a196d1ddf2 decoder/Thread, ...: quote log strings 2024-07-10 15:40:04 +02:00
8861279add Merge branch 'explicit_case_sensitivity' of https://github.com/geneticdrift/MPD 2024-07-10 15:33:47 +02:00
f2f6dc5897 subprojects: update fmt to 11.0.1 2024-07-10 09:32:11 +02:00
00c4abfd2e Merge branch 'opus' of https://github.com/neheb/MPD 2024-07-10 09:27:16 +02:00
2d1feb78b5 subprojects: opus: update to 1.5.2
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-07-09 15:04:43 -07:00
266deaaef1 subprojects: libnpupnp: update to 6.1.3
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-07-09 14:48:37 -07:00
gd
d2382e8de9 ParseStringFilter: when failed to parse the operator, indicate the unknown operator in the error message 2024-07-09 17:25:45 +03:00
gd
c39d8e5813 Added explicitly case sensitive/insensitive filter operators.
The default case sensitivity is hard coded for each command.
These operators allow to override the this default case sensitivity.
2024-07-09 17:25:45 +03:00
bd59c889f3 util/StringVerify: new library 2024-07-08 16:02:40 +02:00
553c2e9e2b output/Command: trigger IDLE_OUTPUT only for the current partition
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1622
2024-07-08 15:54:14 +02:00
bdc5602244 meson.build: update the required GCC/clang versions 2024-07-08 15:44:45 +02:00
3229da48e3 tag/Mask: pass 64 bit integer to constructor, prevent truncation
Commit f49d4ef4ad changed the bit mask size to 64 bit, but I forgot
to change the constructor as well.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2057
2024-07-08 15:34:27 +02:00
e380ae90eb Log: add missing include for std::back_inserter()
Closes https://github.com/MusicPlayerDaemon/MPD/issues/2071
2024-07-07 10:10:27 +02:00
8d15e0fed3 Merge branch 'meson' of https://github.com/leigh123linux/MPD 2024-07-06 13:43:28 +02:00
b459fd3910 Fix bin install location on linux.
For Linux, Meson's default value for bindir is 'bin' [1].
This commit restores mpd's previous functionality of installation in ${prefix}/bin.

[1] https://mesonbuild.com/Builtin-options.html

Fixes https://github.com/MusicPlayerDaemon/MPD/issues/2043
2024-07-06 09:43:01 +01:00
8790f2469c lib/fmt/SocketAddressFormatter: switch to the new net/FormatAddress library 2024-07-05 18:39:10 +02:00
d3ef4ab234 net/FormatAddress: new library to replace ToString.cxx
This library writes to a caller-specified buffer instead of
allocating a std::string which can be faster by avoiding heap
allocations.
2024-07-05 18:38:17 +02:00
fcddab84c6 subprojects: add libnpupnp/GCC14 fix 2024-07-05 18:26:51 +02:00
28c030c0f0 lib/fmt/SocketAddressFormatter: add const for fmt 11 support
See d70729215f
2024-07-05 18:21:38 +02:00
175103e8d4 lib/fmt/ExceptionFormatter: un-inline to reduce header dependencies 2024-07-05 18:20:31 +02:00
3f638eeed6 lib/fmt/SocketAddressFormatter: un-inline to reduce header dependencies 2024-07-05 18:20:31 +02:00
df2be0a75f Log: add missing include for GetFullMessage() 2024-07-05 18:20:31 +02:00
608c2a8c93 .github/workflows/build.yml: add clang build
Due to linker failures, we need to build our own libfmt and
googletest.
2024-07-05 18:05:56 +02:00
2d918bf2c9 .github/workflows/build.yml: add matrix.packages 2024-07-05 17:50:46 +02:00
0bd1289371 .github/workflows/build.yml: remove the forced fallback for libfmt
Ubuntu 24.04 has fmt 9.1.0, so we don't need that anymore.
2024-07-05 17:50:44 +02:00
b2e2d36d79 .github/workflows/build.yml: add Meson option "--wrap-mode nofallback"
The library setup should be well-defined without implicit downloads.
2024-07-05 17:43:39 +02:00
11bb2ad0fd .github/workflows/build_android.yml: update NDK to 27rc1 2024-07-05 17:35:54 +02:00
f37b699349 .github/workflows/build_android.yml: switch to Ubuntu 24.04 as well
Since 24.04 comes with Meson 1.3.2, we can install it with "apt-get"
instead of "pip".
2024-07-05 17:29:37 +02:00
044280c538 meson.build: require Meson 1.0
Debian Bookworm (the current stable) has 1.0.1 and Ubuntu LTS 24.04
has 1.3.2.  It's acceptable to require at least version 1.0 now.
2024-07-05 17:23:52 +02:00
473fb4e19f .github/workflows/build.yml: update GCC 11 build to GCC 14
We only need the oldest supported compiler (i.e. GCC 10) and the
newest one available in the runner (i.e. GCC 14).
2024-07-05 17:21:31 +02:00
404e1c3912 .github/workflows/build.yml: update ubuntu-22.04 to ubuntu-24.04 2024-07-05 17:12:34 +02:00
3648475f87 Merge branch 'libfmt' of https://github.com/heitbaum/MPD 2024-07-05 16:47:04 +02:00
1402869715 lib/fmt: support build with libfmt-11.0.0
Upstream libfmt commit fmtlib/fmt@d707292
now requires the format function to be const.

Adjust the function prototype so it is const and can compile.

Signed-off-by: Rudi Heitbaum <rudi@heitbaum.com>
2024-07-05 14:33:07 +00:00
a64ea486e8 Merge branch 'albumart_doc' of https://github.com/jcorporation/MPD 2024-07-05 16:27:47 +02:00
ffa917e9b5 Merge branch 'stickernames_cmd' of https://github.com/jcorporation/MPD 2024-07-05 16:26:58 +02:00
ac1265b9cc output/alsa: set up the ALSA channel map
This is necessary for proper multi-channel support because many ALSA
drivers do not use the channel maps from surround*.conf.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2063
2024-06-27 21:52:38 +02:00
2ce8310448 time/Convert: forward-declare struct tm 2024-06-25 20:33:13 +02:00
a739eefb01 lib/zlib/Error: derive from std::system_error 2024-06-25 20:32:33 +02:00
432bfa15f4 net/SocketError: move check to IsSocketError() 2024-06-25 20:29:27 +02:00
7b938b4d14 util/Exception: sanitize message strings
This should prevent leaking unsanitized strings from libraries.
2024-06-25 20:29:07 +02:00
abb23ba894 event/EpollEvents: add mapping for EPOLLPRI 2024-06-25 20:28:34 +02:00
cd64f9c422 subprojects: update curl to 8.8.0-1 2024-06-25 20:08:45 +02:00
c65d0cefc1 subprojects: update sqlite3 to 3.46.0-1 2024-06-25 20:08:45 +02:00
799e89af9e python/build/libs.py: update FFmpeg to 7.0.1 2024-06-25 20:08:00 +02:00
381215fd73 *: use std::scoped_lock with implicit template parameter 2024-05-23 20:54:49 +02:00
4fc3230fe6 event/Loop: use std::scoped_lock with implicit template parameter 2024-05-23 20:44:12 +02:00
64bdaa46fb lib/curl/Init: use std::scoped_lock with implicit template parameter 2024-05-23 20:44:12 +02:00
6e16eaebba lib/fmt/SystemError: include <array> only on Windows 2024-05-23 20:31:56 +02:00
a67f7f88e4 util/MimeType: add missing include 2024-05-23 20:31:10 +02:00
ec8f467585 util/Intrusive*: add IWYU pragmas 2024-05-23 20:30:50 +02:00
9e3a66d5bf util/djb_hash: make inline and constexpr
Allows calculating hashes at compile time.
2024-05-23 20:30:17 +02:00
c7409d1e04 util/AllocatedString: add missing include 2024-05-23 20:22:44 +02:00
b64d01677b storage/nfs: optimize OpenFile() 2024-05-17 13:39:42 +02:00
9e8128ecb5 lib/nfs/FileReader: convert path to std::string 2024-05-17 12:54:08 +02:00
131dcce0a1 playlist/Mapper: use Storage::OpenFile() 2024-05-17 12:54:08 +02:00
6dfdd8c1c2 db/update/Walk: use Storage::OpenFile() 2024-05-17 12:54:08 +02:00
1b6c279850 db/update/Paylist: use Storage::OpenFile() 2024-05-17 12:54:08 +02:00
81c778a529 SongUpdate: use Storage::OpenFile() 2024-05-17 12:54:08 +02:00
f578a1cb2b storage/Interface: add virtual method OpenFile()
This should replace most InputStream::Open() calls because it is a
chance to reuse existing resources (e.g. the NFS connection).  No such
optimization is implemented, currently (and the method is not yet used
by anybody).
2024-05-17 12:54:08 +02:00
2576e66a55 input/nfs: cancel the pending read operation on seek 2024-05-17 12:54:08 +02:00
58e3b830e9 lib/nfs/FileReader: clear the read_buffer in CancelRead()
Fixes assertion failure with libnfs 6.
2024-05-17 12:53:35 +02:00
1d35031024 lib/nfs/Connection: merge CancelAndClose() into Cancel() 2024-05-17 12:53:30 +02:00
96b61755da lib/nfs/FileReader: fix doc typo 2024-05-15 21:31:30 +02:00
9f174c56ce playlist/Mapper: postpone the stored playlist error
Fixes another regression by commit
f53cd44c7a - an exception thrown by
playlist_open_in_playlist_dir() would skip over
playlist_open_in_storage().
2024-05-15 21:08:46 +02:00
c8be9662bb playlist/Print: add missing exception handler
This went missing in commit f53cd44c7a
2024-05-15 20:53:55 +02:00
f53cd44c7a playlist/{Stream,Mapper,Any}: propagate exceptions, do not catch&log them
Let the caller handle all the exceptions.
2024-05-15 20:19:57 +02:00
9303764a83 playlist/Print: throw PlaylistError::NoSuchList instead of returning false 2024-05-15 20:19:09 +02:00
a5456a89dc playlist/Length: throw PlaylistError::NoSuchList instead of returning false 2024-05-15 20:15:16 +02:00
c974fc664c playlist/Plugin: add noexcept 2024-05-15 20:02:12 +02:00
eceead671e playlist/Stream: add API documentation 2024-05-15 19:59:57 +02:00
4e7b554605 TagAny, playlist/Mapper: use if with initializer 2024-05-15 15:02:59 +02:00
a701da6386 db/update/InotifyUpdate: use OpenLocalInputStream() 2024-05-15 14:48:32 +02:00
1f47fe47c7 input/Open: move code to WaitReady() 2024-05-15 14:39:40 +02:00
5dd07ac040 test/run_storage: use the OptionParser class for command-line options
Introducing the option "--verbose".
2024-05-15 14:11:25 +02:00
ca8a2aeb7b test/run_storage: print a combined usage text for all commands 2024-05-15 11:17:30 +02:00
57fad1d4b2 test/run_storage: move initialization to class GlobalInit 2024-05-15 10:15:12 +02:00
5c2720a931 .github/workflows/build.yml: drop MINGW32 build
The MINGW32 build has been failing for a while because the MSYS2
repository has dropped MINGW32 versions of various packages in commit
6866be94df

I suppose nobody really uses 32 bit anymore.  I'd like to have a 32
bit test of MPD, just to verify code correctness, but on the other
hand, I don't like solving problems like this MSYS2 packaging problem.
2024-05-15 06:20:57 +02:00
31e583e9f8 lib/nfs: initial support for libnfs API 2
Commit
5e8f7ce273
introduced the libnfs API version 2 which may eventually become libnfs
version 6.

This version detection depends on my pull request
https://github.com/sahlberg/libnfs/pull/468
2024-05-15 06:01:42 +02:00
0ac24e5a24 lib/nfs/FileReader: move code to ReadCallback() 2024-05-15 06:00:37 +02:00
98f53b6d3d lib/nfs/Connection: add DisposablePointer parameter to CancelAndClose()
Just in case somebody needs to free a buffer after the NFS
cancellation has completed.
2024-05-15 06:00:35 +02:00
f5092cb73d util/DisposablePointer: new class 2024-05-15 05:58:23 +02:00
48d3bd1cca lib/nfs/Connection: add API documentation 2024-05-14 19:57:50 +02:00
5cffd4f673 lib/nfs/Connection: remove EnableCloseOnExec() call
SOCK_CLOEXEC has been added to libnfs version 2, and since we require
at least version 4, we can safely remove this call.
2024-05-14 19:51:52 +02:00
416f65fe01 util/RoundPowerOfTwo: new library 2024-05-13 20:25:57 +02:00
64c291ba78 lib/nfs/Connection: suppress bogus clang warning
We do need to capture "this" because we use "this->active_leases", but
clang 18 is too dumb to understand this.
2024-05-13 18:30:05 +02:00
dcde2a0bae lib/nfs/Connection: fix -Wunused-lambda-capture 2024-05-13 18:27:38 +02:00
f0ac0c19b7 lib/nfs/Connection: remove obsolete debug field "in_destroy"
This is obsolete because PrepareDestroyContext() no longer calls
nfs_destroy_context().
2024-05-13 16:53:18 +02:00
ba1b8533a5 lib/nfs/Connection: fix assertion failure on mount timeout
When nfs_destroy_context() is called while nfs_mount_async() is in
progress, libnfs invokes MountCallback(-EINTR) (but only if a NFS RPC
call is in progress; if the TCP connect is in progress, that callback
is not invoked).

If the mount operation had timed out, OnMountTimeout() set
mount_state=FINISHED, which triggered an assertion failure in
MountCallback(); this commit adds a check on whether the mount has
timed out and ignores the MountCallback.
2024-05-13 16:51:44 +02:00
84e8927b1b lib/nfs/FileReader: remove obsolete stat64 cast
Obsoleted (and broken) by commit 9947d3e67f
2024-05-13 12:33:03 +02:00
556300d59a input/InputStream: add [[nodiscard]] 2024-05-13 12:29:16 +02:00
34f7b38f39 input/InputStream: pass std::span<std::byte> to Read() 2024-05-13 12:28:40 +02:00
f28d10d934 decoder/dsdiff: convert pointers to references 2024-05-13 11:34:05 +02:00
d6adc59265 test/run_storage: use FormatISO8601() 2024-05-13 10:37:33 +02:00
c154dc00d7 test/run_storage: use StringIsEqual() 2024-05-13 10:37:25 +02:00
6d5dab38dd input/async: pass std::string_view to constructor 2024-05-13 10:18:18 +02:00
480f4d4cf1 Fix filename list for albumart 2024-05-12 22:17:13 +02:00
f8271fec12 command_available return stickernames only if stickerdb is enabled 2024-05-12 21:23:29 +02:00
4800f1d8f2 storage/Interface: add [[nodiscard]] 2024-05-10 19:08:57 +02:00
48ce8e9fb7 subprojects: update sqlite3 to 3450300 2024-05-10 18:18:04 +02:00
f746e5b7d7 subprojects: update liburing to 2.5 2024-05-10 18:17:52 +02:00
cdce257512 subprojects: update libnpupnp to 6.1.2 2024-05-10 18:17:42 +02:00
227ab998bc lib/nfs/Connection: pass status and data to the NfsClientError ctor
This way, we avoid calling the FormatNfsClientError() which crashes
when nfs_get_error() returns nullptr; that can happen on RPC errors:
then, libnfs's check_nfs4_error() doesn't call nfs_set_error().

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2040
2024-05-10 16:36:29 +02:00
9384bff6f9 lib/nfs/Manager: add method MakeConnection()
This uses the libnfs function nfs_parse_url_dir() which means MPD
gains support for the libnfs arguments like "version".

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2039
2024-05-07 21:22:43 +02:00
9947d3e67f lib/nfs/Connection: use nfs_fstat64_async()
This is 64-bit-safe and anyway, nfs_fstat_async() doesn't work with
NFSv4.
2024-05-07 21:22:40 +02:00
67f01fbdb6 db/plugins/simple/Song: pass StorageFileInfo to UpdateFile()
Eliminates a redundant GetInfo() call.
2024-05-07 21:22:39 +02:00
164b5b0cf3 db/Song, SongUpdate: remove unnecessary c_str() calls
Just case implicitly to std::string_view, which is both simpler and
safer.
2024-05-07 21:13:38 +02:00
56bb1dddd7 lib/nfs/Connection: simplify error handling in OnSocketReady() 2024-05-06 18:35:58 +02:00
e6b1cf540b lib/nfs/Connection: remove unnecessary initializers from MountInternal() 2024-05-06 18:24:36 +02:00
d61c83ace8 lib/nfs/Connection: create the nfs_context in the constructor
Another lifetime simplification.
2024-05-06 18:22:23 +02:00
4139024b3d lib/nfs/Connection: return from OnSocketReady() after error 2024-05-06 18:20:42 +02:00
48fe8666c9 lib/nfs/Connection: call nfs_destroy_context() only in the destructor
This simplifies the lifetime of the nfs_context object.
2024-05-06 18:16:11 +02:00
90a44a0c07 lib/nfs/Connection: replace flag "mount_finished" with enum 2024-05-06 18:16:11 +02:00
e013c19223 storage/nfs: remove unused method EnsureConnected() 2024-05-06 18:16:11 +02:00
4684d05fa6 player/Thread: reset the decoder_starting flag in StopDecoder()
Fixes crash bug (assertion failure) if a new "play" command is handled
while the player thread waits for decoder startup.
2024-05-06 17:38:58 +02:00
1c3a1c842d lib/nfs/Lease: use InstrusiveList instead of std::list 2024-05-06 17:22:36 +02:00
f5127686fe lib/nfs/Connection: pass std::exception_ptr by value 2024-05-06 17:03:21 +02:00
2b0275a1c8 lib/nfs/Connection: pass server and export_name as std::string_view 2024-05-06 17:01:15 +02:00
028693c380 lib/nfs/Manager: forward-declare class ManagedConnection 2024-05-06 16:58:41 +02:00
63920be17e lib/nfs/Connection: make server and export_name const 2024-05-06 16:55:57 +02:00
96888cce9c storage/nfs: pass std::string_view to the NfsStorage ctor 2024-05-06 15:28:01 +02:00
bcc39be784 lib/nfs/Base: use std::string_view 2024-05-06 15:25:55 +02:00
b6314b4c4b lib/nfs/Base: use std::array 2024-05-06 15:22:49 +02:00
23d895415a lib/nfs/meson.build: require libnfs 4.0
All Linux distributions have at least version 4, and thus I cannot
test with older versions.
2024-05-06 14:54:04 +02:00
518ce0187a remove macOS support
There were a few macOS related bug reports on the bug tracker which
have been open for years without a volunteer caring for them.  The
GitHub actions build has also been broken for a long time due to bugs
in the ancient LLVM toolchain shipped with macOS, making macOS an
unsuitable non-Linux target for testing MPD's portability.

All of this makes macOS support an annoying liability for me.  To
avoid more frustration, I'm hereby dropping macOS support completely
from MPD.  Maybe this causes enough pain for a new maintainer to
spawn, but maybe nobody cares, so... let's see.
2024-05-06 14:11:50 +02:00
1c69498c58 .github/workflows/build.yml: do not install yajl on macOS
The Brew package of yajl is broken, it fails to build:

 In file included from ../src/lib/yajl/Handle.cxx:4:
 In file included from ../src/lib/yajl/Handle.hxx:6:
 /opt/homebrew/Cellar/yajl/2.1.0/include/yajl/yajl_parse.h:22:10: fatal error: 'yajl/yajl_common.h' file not found
 #include <yajl/yajl_common.h>
          ^~~~~~~~~~~~~~~~~~~~
 1 error generated.

Therefore, MPD cannot support building with yajl on macOS.
2024-05-06 13:39:02 +02:00
615f6f50ce lib/yajl: drop "yajl/" prefix from #include paths
According to the yajl API documentation, #include lines should have
the "yajl/" path prefix, but the actual pkg-config file contains:

 includedir=${dollar}{prefix}/include/yajl

.. which already contains this directory name, and thus the "yajl/"
prefix cannot work.  Unfortunately, the yajl project hasn't been
maintained for nearly 10 years, and there's little chance this bug
will ever be fixed.
2024-05-06 13:31:34 +02:00
79df6a646b Merge branch 'mpdlib' of https://github.com/DDRBoxman/MPD 2024-05-06 13:03:50 +02:00
89d68fb2af Merge branch 'debian-build-doc' of https://github.com/mxjeff/MPD 2024-05-06 13:03:05 +02:00
03b674ce73 net/meson.build: compile IPv[46]Address.cxx only if TCP is enabled 2024-05-06 12:57:55 +02:00
9c421997bf net/SocketDescriptor: WriteNoWait() uses MSG_NOSIGNAL 2024-05-06 12:55:02 +02:00
3813433e02 test/net/TestLocalSocketAddress: add unit tests for GetLocalRaw() 2024-05-06 12:54:45 +02:00
73509fc189 net/LocalSocketAddress: new class wrapping struct sockaddr_un 2024-05-06 12:54:45 +02:00
7c9b7fa311 net/SocketAddress: use std::string_view::find() instead of std::memchr() 2024-05-06 12:54:45 +02:00
cbba22c947 net/SocketAddress: include IPv[46]Address.hxx only ifdef HAVE_TCP 2024-05-06 12:50:44 +02:00
f8529d4fe6 net/{Allocated,Static}SocketAddress: inline GetLocalRaw() 2024-05-06 12:50:29 +02:00
2a206ef309 net/StaticSocketAddress: add method GetLocalPath() 2024-05-06 12:50:24 +02:00
6200c0dc46 net/StaticSocketAddress: include <string_view> only ifdef HAVE_UN 2024-05-06 12:50:19 +02:00
1760310123 Revert "util/IntrusiveList: allow the last disposer to destroy the IntrusiveList"
This reverts commit 669cbcd25a
("util/IntrusiveList: allow the last disposer to destroy the
IntrusiveList").  It was bad because it could lead to off-by-one crash
bugs when the last item was removed inside the previous item's
disposer.

We need a different solution for the other crash bug that was fixed by
the reverted commit.
2024-05-06 12:49:30 +02:00
c8ed28e9c6 test/util/TestIntrusiveList: add test for clear_and_dispose() with modifying disposer 2024-05-06 12:49:04 +02:00
56d4784b11 util/IntrusiveList: add API documentation 2024-05-06 12:48:53 +02:00
4d3adaa557 event/SocketEvent: erase IMPLICIT_FLAGS in Cancel{Read,Write}()
Without this, calling CancelRead() after ScheduleRead() would leave
the HANGUP scheduled, and the caller could receive HANGUP events over
and over which are never properly handled, leading to a busy loop.

The semantics of this API are hard to get right, because the
IMPLICIT_FLAGS (a property of epoll) are somewhat weird.  But it seems
that this change repairs a side effect of the SocketEvent interface
that seemed counterintuitive.
2024-05-06 12:48:42 +02:00
6830cf9dcf net/AllocatedSocketAddress: add SetLocal() overload with std::string_view 2024-05-06 12:48:42 +02:00
4ba288501d .github/workflows/build.yml: install ccache manually
This eliminates the additionoal "apt-get install" call by
ccache-action.
2024-05-06 12:46:44 +02:00
9dcd0604f2 android: Install the libmpd.so output on android
libmpd.so was getting written as a file called `arm64-v8a` instead of `arm64-v8a/libmpd.so`
2024-05-04 00:13:25 -05:00
5a9b0c7142 doc: debian build, add pkconf build dep.
Build dep on pkconf is not explicitly needed because other dependencies
pull pkconf indirectly (ie libid3tag0-dev), but explicit declaration of
a direct MPD build dep is better IMHO.
2024-04-28 15:06:27 +02:00
823d6c9c0f Merge branch 'android_deps' of https://github.com/DDRBoxman/MPD 2024-04-24 14:52:31 +02:00
57e26eb832 android: Always force wrap deps
This ensures that android is always built with the deps we build
with wrap.

Also put back the asm disable for openssl since the version we use needs
that flag
2024-04-23 17:58:43 -05:00
f9c2c2b558 Remove deprecation flag for volume command 2024-04-23 20:37:55 +02:00
a0e9dfbec2 android: null check intent in onStartCommand
For some reason the type annotations here show @NonNull but that is
actually false according to the documentation under service.

This may be null if the service is being restarted after its process has gone away, and it had previously returned anything except START_STICKY_COMPATIBILITY.
2024-04-23 00:24:32 -05:00
cb6f61cf37 android: Update to NDK 27 2024-04-22 22:34:34 -05:00
964e18ab49 doc: debian build, add libpipewire 2024-04-16 19:51:46 +02:00
709acd8920 doc: debian build, add libsystemd 2024-04-16 19:18:57 +02:00
6f0aecbfb3 doc: debian build, fixed libexpat-dev 2024-04-16 19:05:23 +02:00
7ebe56fdd9 util/SpanCast: allow ToStringView() only with integral char types
This avoids std::string_view specialization that make no sense.
2024-04-16 12:37:08 +02:00
fae235197f util/SpanCast: allow ReferenceAsBytes() only with trivially-copyable
Addd the std::has_unique_object_representations_v constraint so we
cast stuff to std::byte only if this would make sense.
2024-04-16 12:33:36 +02:00
141f518bdd .github/workflows/build.yml: add missing backslashes 2024-04-16 12:10:32 +02:00
d9fefbbc5a .github/workflows/build.yml: run Meson manually without BSFishy/meson-build
This eliminates the options duplication in the "build" and "tests" steps.
2024-04-16 12:07:50 +02:00
122d71a05d .github/workflows/build.yml: build only on Ubuntu 22.04 2024-04-16 12:03:24 +02:00
3b4825dd29 .github/workflows/build.yml: do not install outdated libfmt-dev 2024-04-16 11:51:19 +02:00
0c1ecc96a8 *: let libfmt quote strings 2024-04-16 11:50:18 +02:00
39c9e92f42 lib/fmt: require libfmt 9
Version 9 added the "debug format" which I'd like to use.
2024-04-16 11:50:18 +02:00
08810991c2 .github/workflows/build.yml: install ccache manually
This eliminates the additionoal "apt-get install" call by
ccache-action.
2024-04-16 11:39:40 +02:00
f8581c4d6a doc/user.rst: switch to Debian Bookworm 2024-04-16 11:33:00 +02:00
0d8498f1d1 lib/fmt/SocketAddressFormatter: simpler template syntax 2024-04-16 11:02:36 +02:00
7198db758d lib/fmt/PathFormatter: eliminate AllocatedPath specialization with std::convertible_to<Path> 2024-04-16 11:00:21 +02:00
7a4743d00e config/File: add missing include 2024-04-16 11:00:21 +02:00
ae85c2a979 db/Configured: log debug message when there is no cache directory
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1525
2024-04-16 10:57:28 +02:00
de4bdfcd1f python/build/libs.py: disable the FFmpeg "LEAD MCMP" decoder
This decoder causes linker failures and MPD has no use for it anyway.
2024-04-15 22:28:03 +02:00
9c7b930f8f Merge branch 'alsa-drain-recovery' of https://github.com/borine/MPD 2024-04-15 22:21:53 +02:00
9e8bca4879 python/build/libs.py: update FFmpeg to 7.0 2024-04-15 22:05:08 +02:00
5bd3934c00 python/build/libs.py: update WildMidi to 0.4.6 2024-04-15 22:05:08 +02:00
57212d5a35 player/Thread: remove unnecessary StartDecoder() call
Let Run() do this in the next loop iteration.
2024-04-15 21:49:11 +02:00
7236f83999 player/Thread: do not start the decoder twice
Upon receiving PlayerCommand::QUEUE, call StartDecoder() only if the
decoder is not already starting.  Checking just
DecoderControl::IsIdle() is not enough because the decoder may already
have finished decoding the song before the player has started playing
it and before it had a chance to call CheckDecoderStartup().

Omitting the StartDecoder() call now means it will be started later in
the Run() main loop, after CheckDecoderStartup() has succeeded (which
effectively switches to the song that has already been decoded by the
current decoder).

This fixes an assertion failure when compiled in debug mode
(`-Db_ndebug=false`) and random noise playback in non-debug mode
(`-Db_ndebug=true`).

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1900
2024-04-15 21:39:53 +02:00
c8ece786dd player/Thread: add assert() to StartDecoder()
StartDecoder() must not be called when a decoder is still being
started.  This detects the bug
https://github.com/MusicPlayerDaemon/MPD/issues/1900 earlier.
2024-04-15 21:36:11 +02:00
60fae87e59 doc/mpdconf.example: move "replaygain_limit" to user.rst 2024-04-15 18:58:53 +02:00
3145b10f51 doc/mpdconf.example: remove advanced replay gain settings
Keep the example file short, omit settings that are probably only used
by few users.
2024-04-15 18:55:03 +02:00
75047a26f8 doc/mpdconf.example: fix replaygain_limit description
The description (added by commit 43806d524d) was wrong.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1977
2024-04-15 18:51:27 +02:00
1e4bf90c60 io, net, evnet: quote file names in error messages 2024-04-10 13:36:05 +02:00
b3a31b69ee util/RedBlackTree: fix lost "right" child while swapping with successor
Fixes a tree corruption bug that led to assertion failures.
2024-04-10 13:35:31 +02:00
88475f2e2b util/RedBlackTree: swap colors when swapping with successor
Swapping was incomplete without swapping the colors; this led to
assertion failures under certain conditions.
2024-04-10 13:35:28 +02:00
3cf0896998 test/util/TestIntrusiveTreeSet: add test with large randomized tree, erasing random elements
Test fails currently due to two bugs in the red-black tree
implementation.
2024-04-10 13:35:24 +02:00
e0a53d4747 util/IntrusiveTreeSet: add debug method Check()
Only for the unit test.
2024-04-10 13:35:21 +02:00
669cbcd25a util/IntrusiveList: allow the last disposer to destroy the IntrusiveList
Fixes a use-after-free bug in Co::MultiAwaitable::SetReady() when the
last callback frees the Co::MultiAwaitable owner.
2024-04-10 13:35:09 +02:00
2f7c19f139 util/SpanCast: rewrite ToStringView(std::span<std::byte>) to avoid cast ambiguities 2024-04-10 13:34:51 +02:00
e131f22642 util/SpanCast: merge two ToStringView() using std::remove_const_t 2024-04-10 13:34:25 +02:00
a09e33bf8e Merge branch 'RoboSchmied-AGfixT118' of https://github.com/RoboSchmied/MusicPlayerDaemon-MPD 2024-04-08 08:23:48 +02:00
cd3c34e7b9 Merge branch 'intents' of https://github.com/DDRBoxman/MPD 2024-04-08 08:23:25 +02:00
b3733ef32a Merge branch 'sticker_filters' of https://github.com/jcorporation/MPD 2024-04-08 08:20:28 +02:00
f3b9674fed Fix: 1 typo
Co-authored-by: RoAGmer <no-reply@github.com>
Signed-off-by: RoboSchmied <github@roboschmie.de>
2024-04-07 18:59:40 +02:00
b0cd456753 android: Button to jump to bottom of log view
This adds a button that can jump to the bottom of the log view.
If the user scrolls up we now disable the auto scroll down and show the
down button. When the down button is clicked the auto scroll resumes and
the button is removed.
2024-04-06 20:11:01 -05:00
c613d25f29 Add operators contains and starts_with to sticker find 2024-04-06 20:08:59 +02:00
fff9ceccc2 android: Add intents for service start and stop
org.musicpd.action.StartService
org.musicpd.action.StopService

You can test these actions like:
adb shell am broadcast -a org.musicpd.action.StartService org.musicpd

Calling these from an app like tasker should allow for automation
2024-04-05 23:46:14 -05:00
4bcbeae1e0 android: Move service client into it's own file
The service file was getting harder to read so lets pull the client code
into it's own file
2024-04-05 23:27:41 -05:00
4c56e87e36 lib/curl/Global: remove empty line 2024-04-04 09:18:34 +02:00
011b96ff98 net/UniqueSocketDescriptor: add method MoveToFileDescriptor() 2024-04-04 09:16:44 +02:00
d563f5fc87 decoder/mpg123: use mpg123_ssize_t only on MPG123_API_VERSION >= 47 2024-04-03 23:21:54 +02:00
9c2df5ce19 decoder/mpg123: implement stream_decode 2024-04-03 23:12:26 +02:00
1745c485f3 decoder/mpg123: move code to Scan() 2024-04-03 22:52:56 +02:00
a53db82ae4 decoder/mpg123: move code to Decode() 2024-04-03 22:49:43 +02:00
a20a83eb76 decoder/mpg123: move code to GetAudioFormat() 2024-04-03 22:37:29 +02:00
65e5a43e46 decoder/List: prefer "mpg123" over "mad"
libmad hasn't been maintained for many many years, while libmpg123 is
still maintained.

Our "mad" plugin can't do streams, but MPD will automatically fall
back to "mad" (or "ffmpeg") for streams.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1954
2024-04-03 22:25:34 +02:00
b6afdf1201 util/UriUtil: disable path segment stripping
This bug introduced by commit 49ed9dae34
and activated by commit acc1bd6297
caused leading spaces to disappear from the beginning of all file
names.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1961
2024-04-03 22:00:36 +02:00
08a00ee21b config/PartitionConfig: clip the max_playlist_length setting
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1932
2024-04-03 21:43:39 +02:00
41a1e98cb9 subprojects: update sqlite3 to 3.45.2-1 2024-04-03 21:34:40 +02:00
99da022775 util/IntrusiveSortedList: remove unused class 2024-04-03 21:31:08 +02:00
1ee25b4234 event/TimerList: remove option NO_BOOST
Always use the new IntrusiveTreeSet class.
2024-04-03 21:30:59 +02:00
c5e607a310 event/TimerList: use IntrusiveTreeSet instead of boost::intrusive::multiset 2024-04-03 21:30:31 +02:00
5a0bad3b2f util/IntrusiveTreeSet: new class 2024-04-03 21:29:34 +02:00
6a99f20828 util/IntrusiveHashSet: add concept checks to *Operators
This requires adding another template argument and reordering the others.
2024-04-03 21:27:37 +02:00
91ca502e10 output/httpd/Client: pass std::string_view to HandleLine() 2024-04-03 21:06:11 +02:00
1e5c37ee78 util/SpanCast: add ToStringView() with non-const std::byte
Without this, we would get std::string_view<std::byte> which makes no
sense.
2024-04-03 20:58:03 +02:00
ef2cdc0c6a output/httpd/Client: remove duplicate API docs 2024-04-03 20:50:31 +02:00
c94c08c6b4 event/BufferedSocket: pass std::span to OnSocketInput() 2024-04-03 20:43:40 +02:00
5de8edced6 output/httpd/HttpdClient: convert metaint to a compile-time constant
After all these years, we had this as a field but there was never a
way to change the value.  So let's just hard-code it until we actually
have a reason to make it variable at runtime.
2024-04-03 20:30:53 +02:00
8906ce07de output/httpd/IcyMetaDataServer: pass metaint as std::size_t 2024-04-03 20:29:47 +02:00
9d66fc491c output/httpd/Client: fix API doc syntax 2024-04-03 20:21:18 +02:00
f8a838db5d output/httpd/Client: convert variable to std::string_view
In all cases, we already know the length, and casting the C string to
std::string_view has to call strlen() again.
2024-04-03 20:20:33 +02:00
e4ba736d03 input/{async,rewind}, decoder/dsdiff: use std::cmp_*() for safer integer comparisons 2024-03-15 18:45:46 +01:00
cc291e8c98 Merge branch 'extend-robustness-of-cdda-playback' of https://github.com/lazypingu/MPD 2024-03-15 18:39:45 +01:00
c00d217a53 Skip track if returned LSNs are negative which indicates track errors or if track is not an audio track 2024-03-12 20:39:51 +01:00
9d853897cd Use track and disc functions from libcdio-paranoia to enable playback of hidden tracks and audio tracks on multisession CDs 2024-03-12 20:37:50 +01:00
88c77f9c8a Add debug logging if setting speed failed 2024-03-12 20:37:50 +01:00
1a7278f1d3 Move cddap_speed_set below cddap_open to make sure that the drive was initialized and opened before attemting to set the speed 2024-03-12 20:36:28 +01:00
9916d455f9 python/build/libs: fix libnfs 5.0.3 path 2024-03-11 15:55:25 +01:00
541707f9a8 lib/curl/Easy: add SetRequestBody() overload with std::span 2024-03-11 15:32:24 +01:00
00cf036d58 lib/avahi/Client: relax assertion after COLLISION/REGISTERING
Turns out that `AVAHI_CLIENT_S_COLLISION` can occur after
`AVAHI_CLIENT_S_RUNNING`, and `connected==true`.  Relaxing this fixes
a bogus assertion failure.
2024-03-11 15:32:24 +01:00
9c68f24cfc net/SocketError: fix typo
Whoops.  This function has never been used.
2024-03-11 15:32:24 +01:00
02c4512b00 util/CharUtil: add IsLowerHexDigit() 2024-03-11 15:32:24 +01:00
be84b189dc util, io, net, ...: use "#pragma once" 2024-03-11 15:32:24 +01:00
313f2a1894 python/build/libs: update libnfs to 5.0.3 2024-03-11 15:32:24 +01:00
a1ae1a1e95 python/build/libs: update FFmpeg to 6.1.1 2024-03-11 15:32:24 +01:00
4874bcf8e8 python/build/libs: update libopenmpt to 0.7.4 2024-03-11 15:32:24 +01:00
280ff9211f python/build/libs: update zlib to 1.3.1 2024-03-11 15:32:24 +01:00
494f658dee meson.build: suppress -Wnan-infinity-disabled (clang 18) due to libfmt 2024-03-11 15:32:24 +01:00
c144d0a00d meson.build: build fmt in C++20 mode
Enables `char8_t` support which eliminates clang 18's
`-Wdeprecated-declarations` warning about fmt's use of
`std::string_view<unsigned char>`.
2024-03-11 15:32:24 +01:00
696a36bd5a subprojects: update sqlite3 to 3.45.1-1 2024-03-11 15:32:24 +01:00
3a3fc5e13a subprojects: update openssl to 3.0.8-3 2024-03-11 15:32:24 +01:00
0b89cc306e subprojects: update fmt to 10.2.0-2 2024-03-11 15:32:24 +01:00
dbc68047ad subprojects: update flac to 1.4.3-2 2024-03-11 15:32:24 +01:00
2fdfe3a854 subprojects: update curl to 8.6.0 2024-03-11 15:10:41 +01:00
d685d693e8 input/rewind, archive/iso9660: use use std::cmp_*() for safe integer comparison 2024-03-11 15:09:57 +01:00
b0cfdfa257 client/Idle: consume only idle flags that were subscribed to
Since the very beginning when idle subscriptions where introduced
(commit 0bad84066b), waiting for a certain idle mask would clear
all other idle flags as well.  This would cause idle events to get
lost.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1998
2024-03-11 15:07:07 +01:00
7b6909f2c0 db/update/Walk:FindAncestorLoop: uint64_t inode & device
Previously, inode numbers were truncated to 32 bits, which could lead
to problems on XFS where inodes are 64 bit; this could lead to bogus
"recursive directory found" errors during database update.

[mk: added commit description and NEWS line]

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2000
2024-03-11 13:34:27 +01:00
45553c5f61 This commit adds the sort and window parameter to "sticker find"
The three new compare operators "eq", "gt" and "lt" are casting the values to int.

Sort supports:
- uri: sort by uri
- value: sort by value as string
- value_int: casts value to int

Closes 
2024-03-07 20:52:11 +01:00
1efb9d41db doc/protocol.rst: clarify message event
The term "queue" is used in MPD to refer to the current playlist;
clarify that in this case it refers to the client's message queue.
2024-02-25 19:59:26 +01:00
9292b39cf5 doc/protocol.rst: document max number of subscriptions 2024-02-18 12:42:53 +02:00
9eb26ab90c Merge branch 'countplaylist' of https://github.com/jcorporation/MPD 2024-02-15 11:28:11 +01:00
f801f299c9 New command playlistlength
Count the number of songs and their total playtime in the playlist.
2024-02-15 11:25:34 +01:00
7f18cae2e4 Merge branch 'skidoo23-patch-1' of https://github.com/skidoo23/MPD 2024-02-13 08:06:16 +01:00
a3794f8c3b Allow range in listplaylist and listplaylistinfo 2024-02-08 21:26:28 +01:00
31a88e7ccc Update Templates.cxx
Remove Spotify leftovers
2024-01-26 14:34:58 +01:00
4074e3a9e4 Update Option.hxx 2024-01-26 14:31:08 +01:00
c71e586c53 .readthedocs.yaml: install sphinx-rtd-theme 2024-01-19 10:31:50 +01:00
1039fb5582 .readthedocs.yaml: add 2024-01-19 10:22:36 +01:00
7f60acdfdd util/CharUtil: add IsUpperAlphaNumericASCII() 2024-01-18 18:53:05 +01:00
aef2c5dc14 lib/avahi/Service: add field visible
Now individual services can be hidden or shown at any time.
2024-01-18 18:50:06 +01:00
8d02986b0e lib/avahi/Publisher: add missing defer_register_services.Cancel() calls 2024-01-18 18:50:01 +01:00
461da92064 lib/avahi/Publisher: make the service list dynamic
This allows editing the list of services at any time instead of
passing a constant list at construction time.  To do this, Service
instances are now caller-owned and managed in an IntrusiveList instead
of Publisher-owned in a std::forward_list.
2024-01-18 18:48:27 +01:00
b20b773189 zeroconf/avahi/Helper: embed the Avahi::Publisher without std::unique_ptr 2024-01-18 18:45:51 +01:00
74125c0922 test/meson.build: suppress compiler warnings in GTest headers 2024-01-18 18:42:56 +01:00
5023432802 lib/avahi/Publisher: use DeferEvent for RegisterServices()
Prepares making the service list dyammic; the DeferEvent not only
moves the operation out of the current stack frame, but also allows
combining several AddService() calls.
2024-01-18 18:24:08 +01:00
4a14248004 lib/avahi/Publisher: move code to RegisterServices(AvahiEntryGroup) 2024-01-18 18:24:04 +01:00
1b241fc97a lib/avahi/Publisher: allow RegisterServices() to throw 2024-01-18 18:24:01 +01:00
09d1ab7abe lib/avahi/Publisher: move try/catch in GroupCallback() to the top level 2024-01-18 18:23:57 +01:00
d28cb93835 lib/avahi/Client: add method IsConnected()
Publish only if the client is really connected.
2024-01-18 18:23:52 +01:00
6b43338e06 lib/avahi/Client: add assert() 2024-01-18 18:23:48 +01:00
9a7a49350c lib/avahi/Client: free the AvahiClient on AVAHI_CLIENT_FAILURE
Previously the AvahiClient was only freed when AVAHI_ERR_DISCONNECTED
was detected, but all other error conditions would lead to a memory
leak.
2024-01-18 18:23:45 +01:00
f85629afa6 lib/avahi/Client: is if with initializer 2024-01-18 18:23:42 +01:00
a39473a912 lib/avahi/Service: add API docs 2024-01-18 18:23:37 +01:00
05d0e9b8bb lib/avahi/Publisher: reuse the AvahiEntryGroup
The libavahi-client documentation recommends reusing AvahiEntryGroup
instances instead of freeing them and creating new ones.
2024-01-18 18:23:30 +01:00
b68c3b7f55 net/SocketDescriptor: disable msghdr methods on Windows 2024-01-18 15:44:44 +01:00
0fbed6dec1 net/SocketDescriptor: remove misplaced [[nodiscard]] 2024-01-18 15:44:43 +01:00
16af2a2998 CommandLine: fix typo
I believe this is a typo since all other sections have the form
"<Singular> plugins", e.g. "Encoder plugins".
2024-01-18 14:23:41 +02:00
7a40ac52a8 Merge branch 'bottombar' of https://github.com/DDRBoxman/MPD 2024-01-18 09:59:48 +01:00
6352d1b1ca Merge branch 'sdkcheck' of https://github.com/DDRBoxman/MPD 2024-01-18 09:59:17 +01:00
c93fc161dc Merge branch 'next_prev_fix' of https://github.com/DDRBoxman/MPD 2024-01-18 09:58:39 +01:00
5b7de2bc2f android: Refactor settings UI into screens and add a bottom bar.
This puts Status, logs, and settings all on different tabs. This gives us plenty more room to work to improve these views going forward
2024-01-18 01:23:31 -06:00
04ba7eb987 android: Use build tools and SDK 34
The gradle config for the app is already compiling with the 34 SDK
so lets bump it for the bridge build too
2024-01-17 23:55:01 -06:00
5a2267bdb4 Android: Look for license to verify Android SDK folder
The `android` command was depricated and has been removed from new installs of the sdk

The license file existing is about all that is stable between different sdk versions and
cli vs Android studio installs
2024-01-17 23:46:17 -06:00
0075c57bd4 android: Check playlist state before changing track
Playlist will throw an exception if we call next or previous track when it is not in the "playing" state
2024-01-13 23:23:29 -06:00
87873c9a73 android: Support play / pause from media session 2024-01-13 23:15:56 -06:00
380e0abbe4 python/build/libs.py: fix libopenmpt source path
Fixes regression by commit ea23ea28ce
2024-01-13 22:51:07 +01:00
e4cc89b2d9 Merge branch 'jg' of https://github.com/neheb/MPD 2024-01-13 22:38:34 +01:00
14dea04ee9 test/util: use unsigned integer literals for -Wsign-compare 2024-01-13 22:33:23 +01:00
6f6cbeba80 net/SocketDescriptor: add Send()/Receive() overloads with iovec 2024-01-13 22:32:35 +01:00
974ed0166c net/SocketDescriptor: add sendmsg(), recvmsg() wrappers 2024-01-13 22:31:58 +01:00
a91920a8ff net/SocketDescriptor: pass span<byte> to Read()/Write() 2024-01-13 22:31:34 +01:00
7cd38dde09 net/SocketDescriptor: add [[nodiscard]] 2024-01-13 22:31:24 +01:00
b63a794fbe io/FileDescriptor: add [[nodiscard]] 2024-01-13 22:31:16 +01:00
3e862b85d4 Merge branch 'mediasession' of https://github.com/DDRBoxman/MPD 2024-01-13 22:27:00 +01:00
85bca660d1 Merge branch 'update-failure-response-example' of https://github.com/naglis/MPD 2024-01-13 22:25:00 +01:00
87704f49c9 Merge branch 'NEWS-update' of https://github.com/mxjeff/MPD 2024-01-13 22:24:31 +01:00
9f9cbb8823 Merge branch 'logging' of https://github.com/DDRBoxman/MPD 2024-01-13 22:24:22 +01:00
fa6ef6f1c7 Add NEWS entry about the switch to sphinx_rtd_theme
Change introduced in 6913148d99
2024-01-13 11:32:55 +01:00
db354f5e53 doc/protocol.rst: update failure response example
The commands in the example currently result in `ACK_ERROR_ARG`.
2024-01-10 21:03:26 +02:00
d3335f9947 db/simple: make more fields const 2024-01-08 13:55:15 +01:00
1a67062e1e db/simple: reorder fields to reduce padding 2024-01-08 13:54:15 +01:00
fec1a4ac32 db/simple: pass hide_playlist_targets to sub-instance 2024-01-08 13:53:59 +01:00
7f439b01a3 net/SocketAddress: move code to IsInet() 2024-01-08 13:48:13 +01:00
0fd6f83766 net/StaticSocketAddress: add constexpr 2024-01-08 13:48:05 +01:00
b15b2125e2 net/AddressInfo: add methods IsInet(), IsTCP() 2024-01-08 13:47:59 +01:00
3711bd0d24 android: Implement basic media session handling for next and previous track
This starts a Media3 MediaSession when the service starts. A custom player class gets passed into that session to receive commands from other apps and the android os.

Currently we pad out some dummy items to make SimpleBasePlayer think we can do next and previous tracks.

MPD handles the threading for the native calls so we can just directly call the bridge from the player class.
2024-01-05 18:23:16 -06:00
e086f09d48 android: add next and previous track to the jni bridge
This will allow the android client to directly make calls to the mpd process to change tracks

I went with camel case on the function names here, if you use an underscore
javac generates a function tht looks like this:
 JNIEXPORT void JNICALL Java_org_musicpd_Bridge_play_1previous

I figured what we ended up with looks a little nicer:
JNIEXPORT void JNICALL Java_org_musicpd_Bridge_playPrevious
2024-01-05 18:21:46 -06:00
324bd95c91 android: Move logging into it's own repository class.
Logs will be maintained and appended even when the main UI is not bound to the service.

This also lets us log without filling a Handler with a bunch of messages we might just throw away anyway.
2024-01-04 17:44:49 -06:00
5d122c3bc8 android: Add dependencies and new application class for dagger / hilt support
Dagger and hilt give us dependency injection which makes it easier to split up parts of the app. This lets us easily split out things like logging and paves the way to migrate off preferences to DataStore

This also remove the process name on the service to pull eveything into one process so we don't have to do IPC to pass logs around. This lets us use the same instances of injected classes between the UI and the service side.
2024-01-04 17:44:43 -06:00
8e123e7fc9 test: archive: fix compilation with Windows
NarrowPath is needed.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 14:22:25 -08:00
e8163124e3 mpg123: fix compilation under Windows
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 14:22:25 -08:00
0651be8366 fluidsynth: fix compilation on Windows
NarrowPath is needed.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 14:22:25 -08:00
4957035be6 mikmod: fix compilation on Windows
NarrowPath is needed.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 14:22:25 -08:00
bcd55c0b75 sidplay: fix compilation under Windows
NarrowPath is needed.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 14:22:25 -08:00
914ee92015 wavpack: fix compilation on Windows
NarrowPath is needed.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 14:22:25 -08:00
fb9194b537 tests: fix ChromaPrint test on Windows
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 14:22:24 -08:00
c04490bd52 storage/curl: eliminate std::strings, parse string_view directly 2024-01-04 21:11:07 +01:00
b601f4dc15 util/CNumberParser: remove unused function ParseInt64() 2024-01-04 21:07:50 +01:00
4086190c80 decoder/OpusTags: use ParseInteger() 2024-01-04 21:06:38 +01:00
e1eea9d98a util/NumberParser: new library based on std::from_chars() 2024-01-04 21:03:37 +01:00
393d57b387 util/NumberParser: rename to CNumberParser
A new NumberParser library based on std::from_chars() will be added.
2024-01-04 21:02:45 +01:00
b283fe07af lib/expat/ExpatParser: pass std::string_view to CharacterData() 2024-01-04 20:55:14 +01:00
feeb21577f lib/upnp/Device: use std::forward_list instead of std::vector 2024-01-04 20:51:20 +01:00
1fca16737d lib/upnp/Device: remove unnecessary ctors/dtors 2024-01-04 20:49:27 +01:00
4ec85a12e3 lib/upnp/Discovery: use std::map instead of std::list 2024-01-04 20:45:24 +01:00
3d2aebccad lib/upnp/Discovery: pass std::string_view to LockRemove() 2024-01-04 20:40:47 +01:00
22382f799c lib/upnp/Discovery: add noexcept 2024-01-04 20:39:21 +01:00
468eceabff lib/upnp/Discovery: remove unreachable exception handler 2024-01-04 18:04:46 +01:00
08e0eb79f5 lib/upnp/Discovery: remove unused default ctor 2024-01-04 18:04:21 +01:00
8b03ce562c input/curl: increase CURLOPT_BUFFERSIZE from 16 kB to 512 kB 2024-01-04 17:57:42 +01:00
997311ba14 lib/curl/Easy: add method TrySetOption() 2024-01-04 17:51:48 +01:00
cbd031ca7f lib/upnp/Action: common UpnpSendAction() wrapper for pupnp and npupnp
Merge a lot of duplicate code.
2024-01-04 17:40:59 +01:00
95842e7984 db/upnp: eliminate the std::forward_list, use IterableSplitString() 2024-01-04 16:31:28 +01:00
cc41e95806 db/upnp: add rootid_sv 2024-01-04 16:20:44 +01:00
2c77e088b4 db/upnp: eliminate temporary std::string from Visit() 2024-01-04 16:19:03 +01:00
4eefc2e47c test/DumpDatabase: add "URI" parameter 2024-01-04 15:37:10 +01:00
7c13666226 test/DumpDatabase: remove the "PLUGIN" parameter, load from config file 2024-01-04 15:36:18 +01:00
4ed8313954 test/DumpDatabase: use libfmt 2024-01-04 15:32:26 +01:00
c8e2ab6781 db/upnp/Object: smaller enums 2024-01-04 14:31:41 +01:00
b2ed29b8c0 lib/upnp/ContentDirectoryService: getFriendlyName() returns std::string reference
This can avoid the overhead of casting a C string back to std::string_view.
2024-01-04 14:28:12 +01:00
1789b56a85 db/upnp: pass std::string_view to songPath() 2024-01-04 14:28:12 +01:00
714dbc9294 lib/upnp/Discovery: forward-declare inner class ContentDirectoryDescriptor 2024-01-04 14:28:12 +01:00
f40eb963fd lib/upnp/Discovery: forward-declare inner class Downloader 2024-01-04 14:28:12 +01:00
ee4b49d12f lib/expat/ExpatParser: pass std::string_view to Parse() 2024-01-04 14:28:12 +01:00
4c9942534c lib/upnp/Device: pass url as std::string_view to Parse() 2024-01-04 14:28:12 +01:00
d5f7db59a8 lib/upnp/Util: pass std::string_view to path_getfather() 2024-01-04 14:28:12 +01:00
8d1b73ae89 lib/upnp/Discovery: use string_view::starts_with() instead of strncmp() 2024-01-04 14:28:08 +01:00
afa77099cf msys2 CI
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 12:49:43 +01:00
f68fab53a7 zzip: fix compilation on Windows
NarrowPath is needed.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 12:38:36 +01:00
6a4dc281d1 bzip2: fix compilation on Windows
NarrowPath is needed.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-04 12:38:30 +01:00
26831a417a subproject: update expat to 2.5.0-4 2024-01-04 09:49:10 +01:00
6293818c35 subproject: update fmt to 10.2.0-1 2024-01-04 09:49:09 +01:00
a859de6806 sndfile: fix compilation with clang's libc++
error: non-constant-expression cannot be narrowed from type 'sf_count_t'
(aka 'long long') to 'size_type' (aka 'unsigned int') in initializer list
 [-Wc++11-narrowing]
  215 |                      std::span{buffer, num_frames * frame_size},
      |                                        ^~~~~~~~~~~~~~~~~~~~~~~
note: insert an explicit cast to silence this issue
  215 |                      std::span{buffer, num_frames * frame_size},
      |                                        ^~~~~~~~~~~~~~~~~~~~~~~
      |                                        static_cast<size_type>()

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2024-01-03 12:18:52 -08:00
13202bfce4 test: neighbor_explorer: fix compilation on WIN32
Need NarrowPath. Matches what is done in other tests.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2023-12-31 15:38:49 -08:00
f3d031b38a libnpupnp: update subproject
Fixes compilation under Windows.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2023-12-31 13:58:10 -08:00
f6dbf38e99 upnp: change interface variable name
rpc.h under Windows defines interface as struct, which blows up the
build here. Rename to avoid.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2023-12-28 19:39:05 -08:00
d0a4270449 lib/upnp/Compat: remove obsolete kludges
Those bugs have been fixed looong ago.
2023-12-28 21:24:58 +01:00
b9a7a9981e lib/upnp/ContentDirectoryService: remove unused fields 2023-12-28 21:22:41 +01:00
d9fb152b95 lib/upnp/ContentDirectoryService: include some headers only with libpupnp 2023-12-28 21:18:41 +01:00
09a0f7a45c Merge branch 'android_fix' of https://github.com/DDRBoxman/MPD 2023-12-28 21:02:49 +01:00
9396ffb509 db/plugins/upnp/ContentDirectoryService: add missing closing curly brace 2023-12-28 20:52:53 +01:00
66a8afd18c subprojects: add libnpupnp 2023-12-28 20:51:13 +01:00
e7e07c39c5 meson: fix flac_dep under Windows
declare_dependency's found() method evaluates to true always, resulting
in MPD trying to build flac when not found. Check for dependency()'s
find() first.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2023-12-27 12:43:08 -08:00
201e081750 android: Fix boot receiver settings and intent check 2023-12-27 13:38:38 -06:00
5f7f1d738d android: set kotlin target to 9
The naming scheme was changed in kotlin but not java after java 8
2023-12-27 13:34:37 -06:00
8a3d144714 android: Set kotlin jvm target to 1.9 2023-12-27 13:27:02 -06:00
44080154b0 no setenv on Windows
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2023-12-27 10:50:00 -08:00
c17493f2d3 Merge branch 'fs' of https://github.com/neheb/MPD 2023-12-27 12:38:30 +01:00
dcfc1ca6a0 Merge branch 'doc-time-case' of https://github.com/naglis/MPD 2023-12-27 12:37:58 +01:00
07e1bae0af Merge branch 'doc-config-comments' of https://github.com/naglis/MPD 2023-12-27 12:35:32 +01:00
658a7f1ca7 Merge branch 'material' of https://github.com/DDRBoxman/MPD 2023-12-27 12:35:13 +01:00
bd408cd627 Merge branch 'bootfix' of https://github.com/DDRBoxman/MPD 2023-12-27 12:33:14 +01:00
7c520f6475 fs: fix typo
Wrong macro used.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2023-12-26 10:57:44 -08:00
07ee11b963 doc/protocol.rst: fix time tag case
The `Time` song tag starts with an uppercase letter.
2023-12-26 10:51:34 +02:00
a4c7041561 subprojects: properly export id3tag include headers
According to the Makefile.am from libid3 only i3dtag.h should be installed to the include directory.
include_HEADERS =	id3tag.h
2023-12-24 11:31:29 -06:00
d7eb223343 doc: mention config file comment syntax 2023-12-23 09:33:01 +02:00
ddc048e2c3 android: Move settings to compose and material UI 3
This changes lets us use the latest UI design from Google, Material 3.

Google only provides the material UI 3 themes for compose, compose only works with kotlin.
2023-12-22 23:04:51 -06:00
625ab6decd android: Move preferences class out of settings 2023-12-22 22:51:14 -06:00
2638396df5 android: add dependencies for Material 3 and Compose 2023-12-22 13:30:43 -06:00
3d8e285e2b android: Fix launching on device boot 2023-12-22 12:30:45 -06:00
793a12d58d android: Use Java 9 2023-12-22 12:30:27 -06:00
23b4688c44 util/ByteOrder: move Packed* classes to separate headers 2023-12-22 18:20:46 +01:00
c4d8888972 subprojects: add id3tag 2023-12-22 18:15:25 +01:00
6e50031c49 python/build/libs.py: remove libmad (unused) 2023-12-22 18:05:40 +01:00
833ca1e350 test/dump_rva2: fix TCHAR/char confusion on Windows 2023-12-22 18:05:40 +01:00
a888b3a707 decoder/plugins/meson.build: add missing dependency to libid3tag 2023-12-22 18:03:47 +01:00
d9bbe39f48 android/include/meson.build: remove custom "-I" flag
This is not necessary because the declared dependency is enough for
Meson to generate the "-I" flag automatically.
2023-12-22 17:07:50 +01:00
38226dfe81 android/include/meson.build: generate *.class in @PRIVATE_DIR@
We're not interested in the *.class files, we run javac only to
generate the JNI header.  By using @PRIVATE_DIR@, it gets stored to a
directory we can ignore, and not into the source tree.
2023-12-22 16:46:25 +01:00
94ef1e13e0 android/include/meson.build: call javac directly, eliminate run-javac.sh 2023-12-22 16:41:35 +01:00
35c7c005ba android/meson.build: move target org_musicpd_Bridge.h to include/meson.build 2023-12-22 16:39:13 +01:00
1e732f9b9b android/run-javac.sh: remove unnecessary realpath call 2023-12-22 16:35:06 +01:00
ee5c471280 android/meson.build: pass @OUTDIR@ to run-javac.sh 2023-12-22 16:32:10 +01:00
8ef47147a0 .github/workflows/build_android.yml: do not ignore "python"
Python scripts are used to build Android.
2023-12-22 15:17:47 +01:00
fb4dd4e1ce .github/workflows/build_android.yml: remove branch v0.23.x
This branch cannot be built this way.
2023-12-22 15:17:45 +01:00
a19f3a4f9f python/build/meson.py: put ccache prefix in array instead of stripping it
Turns out Meson disables ccache auto-detection when a cross-file is
used.  To use ccache, the ccache prefix must be expressed in an array
instead of a single string with spaces.
2023-12-22 15:11:53 +01:00
c3ba52a1fc python/build/toolchain.py: auto-detect ccache 2023-12-22 15:05:41 +01:00
1b2bd0cc0a .github/workflows/build_android.yml: use preinstalled Android SDK/NDK 2023-12-22 14:39:20 +01:00
dd3779d64b .github/workflows/build_android.yml: use preinstalled Java 2023-12-22 14:39:20 +01:00
806d1483a8 .github/workflows/build_android.yml: install Meson 1.3.0
We need at least 0.63.0 for "diff_files" support in subprojects;
without this, the Opus build breaks.
2023-12-22 14:39:20 +01:00
b1f28d6003 output/alsa: Fix (theoretical error in) ALSA device recovery
It is not possible to prepare an ALSA device when it is is state
SND_PCM_STATE_OPEN; it is necessary to set the hardware parameters
first.

This pedantic commit corrects that error. Note that in practice
this code path cannot be encountered because MPD always sets the
hardware parameters before attempting to start playback.
2023-12-22 12:02:33 +00:00
50e6950fa8 output/alsa: handle recoverable errors in DrainInternal()
It is possible that an underrun may occur in the ALSA output
device while MPD is draining its own internal buffer. If this
happens then MPD stops playback, reporting the error EPIPE.

This commit attempts to recover the ALSA device instead of
stopping playback, so that the drain can complete and the next
song in the play queue is played.
2023-12-22 11:53:20 +00:00
1d60d3cd2b subprojects: update libmpdclient to 2.22
2.22 fixes the "version.h" conflict.

Closes https://github.com/MusicPlayerDaemon/MPD/pull/1927
2023-12-22 12:08:02 +01:00
59ed18e112 Merge branch 'android_network_address' of https://github.com/DDRBoxman/MPD 2023-12-22 10:26:36 +01:00
c4c1044427 android: Add a text field to display the devices network address 2023-12-21 11:50:10 -06:00
791b3c65f3 python/build/meson: bringt back configure()
This reverts part of commit a3765cd363.
The MesonProject class was not used, but the "configure" function.
2023-12-21 12:02:05 +01:00
a3765cd363 python/build: remove Meson project support
Obsolete, we're now using Meson subprojects.
2023-12-21 11:50:33 +01:00
3c5b864396 tag/IcyMetadataParser: use std::span 2023-12-21 08:42:23 +01:00
b09654b53a build: Remove absolute path on pkg-config
This allows it to be found on macOS and should fix linking libnfs with builds of the Android app
2023-12-20 23:23:18 -06:00
58fc857a2d tag/IcyMetadataParser: pass std::string_view to icy_parse_tag() 2023-12-20 20:18:39 +01:00
e443ee357a tag/IcyMetadataParser: do not null-terminate strings in icy_parse_tag()
Just pass std::string_views into the unmodified buffer to
icy_parse_tag_item().
2023-12-20 19:58:35 +01:00
2618294eb7 tag/IcyMetadataParser: pass std::string_view to icy_parse_tag_item() 2023-12-20 19:51:22 +01:00
03352cb4ad tag/IcyMetadataParser: use std::byte in ParseInPlace() 2023-12-20 19:49:08 +01:00
2c851498cc meson.build: do not leak CPP macros to subprojects 2023-12-20 17:49:13 +01:00
a52292ae17 subprojects: update sqlite to 3.44.2-1 2023-12-20 17:34:05 +01:00
f6a886f092 subprojects: update curl to 8.5.0-2 2023-12-20 17:33:28 +01:00
6234ae5a8b doc/user.rst: do not name the deprecated /var/run/ directory 2023-12-20 17:32:13 +01:00
a4ead670ed subprojects: add libmpdclient wrap 2023-12-20 17:15:29 +01:00
303d981099 subprojects: add lame 2023-12-20 16:50:13 +01:00
7727311df7 meson.build: disable "openssl:asm"
Work around "call to undeclared function "asm" on Android.
2023-12-20 16:30:16 +01:00
5f54a8e94e Merge tag 'v0.23.15'
release v0.23.15
2023-12-20 16:23:58 +01:00
7727630f24 Merge branch 'alsa_input_exception' of https://github.com/borine/MPD 2023-12-20 13:21:37 +01:00
e2f8c9a4c2 Merge branch 'android_action' of https://github.com/DDRBoxman/MPD 2023-12-20 10:55:44 +01:00
22dbfec126 Merge branch 'android_shutdown' of https://github.com/DDRBoxman/MPD 2023-12-20 10:54:35 +01:00
efc462eebf Merge branch 'doc-features' of https://github.com/mxjeff/MPD 2023-12-20 10:53:34 +01:00
c3883e2fe0 Merge pull request from MusicPlayerDaemon/dependabot/github_actions/actions/setup-python-5
build(deps): bump actions/setup-python from 4 to 5
2023-12-20 10:53:16 +01:00
16c91a3f4b android: Fix MPD shutdown from settings UI 2023-12-19 22:05:03 -06:00
80bb5a0542 android: Add github action
This lives under a separate workflow so it can have different ignore paths.
2023-12-19 17:25:25 -06:00
906d58a918 android: migrate app build system to use gradle
Most of the Android specific meson code has been removed and replaced with
the grade build system.

The new meson build scripts build and move the libmpd.so binaries into the correct
location that gradle expects. After than gradle handles building the rest of the Android app.

Icons and banners have been updated for the modern app packaging expectations.

For reference here was the figma template Google provides that I used to back the png versions
for older versions of Android <https://www.figma.com/community/file/1283953738855070149>
2023-12-17 22:38:34 -06:00
23b34fe142 Document new added-since filter introduced in 1615fbc 2023-12-17 10:00:19 +01:00
8d6f503e04 android: require NDK r26b
This fixes `no member named 'invocable' in namespace 'std'`
2023-12-13 12:01:30 -06:00
3284a61f43 android: build with java 8 target
The latest Android `sdkmanager` tool requires a version of the jdk that no longer
supports Java 7 as a target
2023-12-13 11:50:21 -06:00
c1a852d0e8 android: Pick toolchain based on current OS 2023-12-13 11:48:22 -06:00
4c90ad3704 android: realdir doesn't accept nonexistant files on macOS 2023-12-13 11:47:18 -06:00
a92a801f08 android: List additional build dependencies in instructions 2023-12-13 10:38:51 -06:00
9059c6c657 android: find apksigner in build tools folder 2023-12-13 10:35:52 -06:00
bd6f8cd585 build(deps): bump actions/setup-python from 4 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-11 15:18:48 +00:00
a6024f476a subprojects: add openssl 2023-12-11 11:01:32 +01:00
dfef30a737 subprojects: add curl 2023-12-11 10:53:43 +01:00
55ca3709ef subprojects: add ogg, flac, opus 2023-12-11 10:53:43 +01:00
ab6ae7520d doc/developer.rst: add missing return type to code style sample 2023-12-10 08:24:05 +01:00
c7a300d12d meson.build: static liburing wrap build 2023-12-09 21:00:18 +01:00
babf322695 subprojects: update liburing to 2.4-2 2023-12-09 20:55:13 +01:00
642de1510b lib/curl/Request: remove redundant CurlEasy wrapper methods 2023-12-09 20:54:21 +01:00
f61eed1a82 input/plugins/Alsa: catch all exceptions
snd_pcm_poll_descriptors_revents() may return any error code; the
ALSA docs do not constrain the permitted values. A 'hw' device
will only ever return an error if the pfd array passed in is
invalid (-EINVAL), but other I/O plugins may return arbitary
errors. For example a network-based device may return -EPIPE etc.
The resulting exception thrown by
AlsaNonBlockPcm::DispatchSockets() must be caught to prevent the
mpd process from being aborted.
2023-11-26 15:36:42 +00:00
e9c40dead8 output/SharedPipeConsumer: add noexcept 2023-11-26 08:48:45 +01:00
31bf6d29b9 BulkEdit: forbid copying 2023-11-26 08:47:06 +01:00
571b6f0cdb queue/IdTable: add constexpr (because we can) 2023-11-26 08:43:50 +01:00
e7b9e8de14 queue/IdTable: add API docs 2023-11-26 08:43:20 +01:00
321553d5f9 queue/IdTable: add explicit 2023-11-26 08:41:57 +01:00
4d23068c5c queue/IdTable: use C++11 initializer 2023-11-26 08:41:19 +01:00
634b38169a Merge branch 'alsa_input_buffer' of https://github.com/borine/MPD 2023-11-26 08:24:51 +01:00
fe4695f92a Merge branch 'added_time_proxy_plugin' of https://github.com/jcorporation/MPD 2023-11-26 08:20:18 +01:00
3c7941b24b Instance: work around -Wunused-parameter 2023-11-26 08:13:57 +01:00
a5d7f5e1fa client/Client: add interface IClient
This allows detangling dependencies and fixes a linker problem in
test/test_translate_song.cxx.
2023-11-26 08:11:06 +01:00
0dfd7e3d8c net/SocketDescriptor: SO_PROTOCOL is really Linux-specific 2023-11-25 23:03:30 +01:00
f757dfdc4f SongLoader: add noexcept 2023-11-25 22:57:24 +01:00
eb675ad1b1 pcm/meson.build: add missing dependency on libconfig.a 2023-11-25 22:51:43 +01:00
08a5768764 fs/io/TextFile: split into class FileLineReader and AutoGunzipFileLineReader
Detangle dependencies.
2023-11-25 22:50:32 +01:00
d888bb1902 io/meson.build: move libfmt dependency to libio.a 2023-11-25 22:16:47 +01:00
6dc708f53f net/SocketDescriptor: use method GetOption() internally 2023-11-25 21:58:17 +01:00
60033f3eb4 net/SocketDescriptor: add method GetProtocol() 2023-11-25 21:58:09 +01:00
1239e075b8 net/SocketDescriptor: add method GetIntOption() 2023-11-25 21:56:07 +01:00
85286d74ef python/build/libs.py: update CURL to 8.4.0 2023-11-25 21:52:41 +01:00
f8f646497c python/build/libs.py: update OpenSSL to 3.1.4 2023-11-25 21:52:41 +01:00
24ace6da25 python/build/libs.py: update FFmpeg to 6.1 2023-11-25 21:52:41 +01:00
ea23ea28ce python/build/libs.py: update openmpt to 0.7.3 2023-11-25 21:52:41 +01:00
4072a6e445 python/build/cmake.py: add CMAKE_FIND_ROOT_PATH on Windows
Works around CURL build failure because cmake insists on using
/usr/include/zlib.h.
2023-11-25 21:52:41 +01:00
54601b292a subprojects: update liburing to 2.4-1 2023-11-25 21:52:41 +01:00
964e193fcd subprojects: update sqlite to 3.44.1-1 2023-11-25 21:52:41 +01:00
d5909b6d5d subprojects: update expat to 2.5.0-3 2023-11-25 20:47:43 +01:00
67a00ee541 subprojects: update fmt to 10.1.1-1 2023-11-25 20:47:11 +01:00
d0eea87b1a song/*SongFilter: use libfmt 2023-11-25 20:42:50 +01:00
273fc329e0 Merge branch 'added-since' of https://github.com/jcorporation/MPD 2023-11-25 20:36:38 +01:00
d85be95c30 Merge branch 'doc-mention-song-id-lifetime' of https://github.com/naglis/MPD 2023-11-25 20:34:40 +01:00
ff60cf8a4c Document new added attribute introduced in 7bf43a97 2023-11-25 14:40:03 +01:00
b9daeef524 event/FineTimerEvent: add SetDue(), ScheduleCurrent() 2023-11-21 20:47:29 +01:00
9383ceac30 event/{Coarse,Fine}TimerEvent: add API docs 2023-11-21 20:47:25 +01:00
3d2bd08132 test/meson.build: eliminate variable gtest_main_dep 2023-11-21 20:46:10 +01:00
1259fdc2e3 test/meson.build: re-enable various compiler warnings with GTest 2023-11-21 20:46:10 +01:00
a564b7eedb test/test_translate_song: remove unused Log() symbol 2023-11-21 20:46:10 +01:00
ebf1fc7ca4 util/IntrusiveList: convert static_assert to concept check 2023-11-21 20:42:01 +01:00
73708e7be7 event/TimerEvent: remove transitional header 2023-11-21 20:41:55 +01:00
0c409aa290 input/LastInputStream: use CoarseTimerEvent 2023-11-21 20:41:47 +01:00
edfa329e64 util/DereferenceIterator: use *declval() to guess the default value type
This allows the iterator to point to another iterator.
2023-11-21 20:40:47 +01:00
5ab2c31500 Merge branch 'v0.23.x' 2023-11-21 20:37:46 +01:00
ce178c7e1f doc/protocol.rst: mention song id lifetime 2023-11-16 22:58:07 +02:00
1615fbc30e Add "added-since" filter expression 2023-11-04 17:25:24 +01:00
45a4fcab1e Add support for added attribute to proxy plugin 2023-11-02 21:22:48 +01:00
68b19ae087 util/SpanCast: add ReferenceAsWritableBytes() 2023-11-02 10:50:24 +01:00
a073db1e52 util/SpanCast: add ReferenceAsBytes() 2023-11-02 10:50:00 +01:00
10940da381 util/Intrusive{List,HashSet}: add "tag" for base hooks 2023-11-02 10:48:46 +01:00
57d9cffc42 event/PipeEvent: expose the EventPollBackendEvents constants 2023-11-02 10:48:21 +01:00
65a3062f45 Merge branch 'configure-systemd-units-based-on-build-options' of https://github.com/naglis/MPD 2023-11-02 10:43:02 +01:00
ac25f3456a Merge branch 'added_time' of https://github.com/jcorporation/MPD 2023-11-02 10:42:31 +01:00
f4f79a3d5f New command "stickernames" lists uniq and sorted sticker names 2023-10-21 18:21:03 +02:00
7bf43a9712 Add "added" timestamp to song database
- added is set to current time, if a new song is added to the database.
- GetAdded falls back to mtime.

Code for proxy plugin is missing, this needs a patch for libmpdclient.

closes 
2023-10-20 17:29:31 +02:00
97da29cc90 Stickers: fix documentation typos 2023-10-16 14:25:58 +01:00
de1da485ab LICENSES: add all licenses referred to by SPDX headers
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1877
2023-10-15 11:39:08 +02:00
2b10cf3c15 pcm/Normalizer: change license identifier to LGPL-2.1-only
"LGPL-2.1" doesn't exist, and the old copyright header did not specify
the "or later" clause, so I must assume it's 2.1 only.
2023-10-15 11:37:21 +02:00
gd
432675d4c2 Stickers: added support for stickers on playlists and some tag types 2023-10-15 11:25:16 +02:00
70ac638d93 tag/Mask: make everything constexpr 2023-10-15 11:03:56 +02:00
ccbacb369b io/linux/ProcPath: new library 2023-10-15 10:55:32 +02:00
7c0b561a16 event/InotifyEvent: add method TryAddWatch() 2023-10-15 10:51:06 +02:00
db5f270f42 util/AllocatedString: fix string_view specialization in TotalSize() 2023-10-09 14:54:40 +02:00
3a86956257 Merge tag 'v0.23.14'
release v0.23.14
2023-10-08 10:12:34 +02:00
f49d4ef4ad tag/Mask: switch to 64 bit because have we 34 tags now and 32 bits are not enough 2023-10-08 10:02:50 +02:00
2859845567 Merge branch 'v0.23.x' 2023-10-08 10:02:19 +02:00
e521b58b01 io/PeekReader: fix offset/size mixup
Regression by commit 7ccc4ddf0d
2023-10-08 09:55:59 +02:00
34182990ef fs/FileInfo: add fstat() wrapper 2023-10-07 12:49:07 +02:00
1ca5d6baa6 io/FileReader: do not copy the path 2023-10-07 12:48:03 +02:00
9365f68454 io/FileReader: use GetFileInfoByHandle() 2023-10-07 12:47:57 +02:00
7b5f107341 fs/FileInfo: add GetFileInformationByHandleEx() wrapper 2023-10-07 12:37:49 +02:00
e9ec03f769 PlaylistFile: use uint_least64_t 2023-10-07 12:29:14 +02:00
579a6ee299 fs/FileInfo: un-inline the constructor to reduce header dependencies 2023-10-07 12:28:31 +02:00
7d31659137 PlaylistFile: add missing include 2023-10-07 12:28:31 +02:00
f549c611ab fs/FileInfo: make constructor explicit 2023-10-07 12:24:05 +02:00
51c0a03e94 fs/FileInfo: add constexpr and noexcept 2023-10-07 12:22:54 +02:00
19c73680cf io/FileReader: use uint_least64_t 2023-10-07 08:49:04 +02:00
a9ba9a5f92 io/Reader: add [[nodiscard]] 2023-10-07 08:45:59 +02:00
3032792563 io/Reader: add method ReadFull() 2023-10-07 08:45:52 +02:00
7ccc4ddf0d io/Reader: use std::span 2023-10-07 08:44:42 +02:00
b9704715fb io/FileOutputStream: pass dfd=-1 for absolute /proc/self/fd/N path 2023-10-07 08:42:35 +02:00
86e7dff2fc util/TextFile: add missing cast 2023-10-07 08:39:24 +02:00
c450f644e6 lib/xiph/OggSyncState: fix indent 2023-10-07 08:30:12 +02:00
496184b1bc io/Reader: add method ReadT() 2023-10-07 08:27:13 +02:00
b81cac3305 lib/nfs/Error: include cleanup 2023-10-04 23:12:45 +02:00
bf9dd24536 lib/pcre/UniqueRegex: wrap Compile() options in struct 2023-10-04 17:32:12 +02:00
e5680c712b util/IntrusiveList: add reverse_iterator 2023-10-04 16:51:17 +02:00
44daa6d3e6 util/IntrusiveForwardList: reset last_cache properly in clear() 2023-10-04 16:50:46 +02:00
5ddddbb16f test/util/TestIntrusiveForwardList: add push_back() test 2023-10-04 16:50:38 +02:00
5aaa3f50aa util/BindMethod: move SignatureHelper to return type 2023-10-04 16:50:25 +02:00
7d26cd74c1 util/BindMethod: add noexcept 2023-10-04 16:50:25 +02:00
7e6941acc8 util/BindMethod: add constexpr 2023-10-04 16:50:25 +02:00
63d865666e util/StringBuffer: use using instead of typedef 2023-10-04 16:50:25 +02:00
5dda4084df util/BindMethod: use using instead of typedef 2023-10-04 16:50:25 +02:00
19f9238ef0 util/BindMethod: fix indent 2023-10-04 16:50:25 +02:00
491cc8f54d net/SocketDescriptor: add {Read,Write}NoWait()
It was surprising that Read() was non-blocking, but there was no
blocking version of it.  Let's make the non-blocking behavior explicit
and change Read() to be blocking.

In order to find existing callers easily with compiler errors, this
also refactors Read()/Write() to take a std::span parameter.
2023-09-27 11:39:55 +02:00
cad35a83fb io/FileDescriptor: add Read()/Write() overloads with std::span 2023-09-27 11:14:23 +02:00
5fbe5951ab output/snapcast/Client: use SocketDescriptor::Send() 2023-09-27 10:39:48 +02:00
21590e60e6 event/FullyBufferedSocket: pass std::span to DirectWrite() 2023-09-27 10:36:56 +02:00
fe69ad0861 event/BufferedSocket: pass std::span to DirectRead() 2023-09-27 10:34:50 +02:00
9daf8f6de5 event/BufferedSocket: use std::byte 2023-09-27 10:30:09 +02:00
8ca6606323 net/SocketDescriptor: move code to Receive(), Send() 2023-09-27 10:16:21 +02:00
09a2da89a2 io/FileDescriptor: pass std::span to Full{Read,Write}() 2023-09-27 10:14:02 +02:00
9a0b3775d8 encoder/ToOutputStream: add API docs 2023-09-26 15:48:55 +02:00
2075a9a999 encoder/ToOutputStream: remove unnecessary cast 2023-09-26 15:48:22 +02:00
1090cc964a event/Loop: relicense to BSD-2
This library has been initially developed at CM4all and eventually
published here:
 https://github.com/CM4all/libcommon/tree/master/src/event/

On this copy of it, there were only minor modifications by people
other than me, and these are below the copyright threshold; only
non-epoll backends (which remain under the GPL) were developed by
somebody else.
2023-09-26 15:47:09 +02:00
39476bed85 Merge branch 'v0.23.x' 2023-09-26 15:36:26 +02:00
5cea03bb4f Merge branch 'v0.23.x' 2023-09-26 11:49:30 +02:00
26467e61a3 Merge branch 'consume_single_oneshot-restore' of https://github.com/jcorporation/MPD 2023-09-26 11:43:27 +02:00
2bb4c7cfa7 test/meson.build: add missing libfmt dependency
Should have been part of 64647edbe1
2023-09-26 10:47:52 +02:00
fbdd2324a5 sticker/Database: add method Reopen() 2023-09-26 10:14:05 +02:00
dc31aa6a61 decoder/Plugin: remove unused and broken wrapper method ContainerScan() 2023-09-26 10:13:42 +02:00
5b28a987e5 util/IntrusiveForwardList: add method remove_and_dispose_if() 2023-09-22 11:32:40 +02:00
78d28063c4 util/IntrusiveForwardList: push_{front,back}() returns iterator 2023-09-22 11:32:33 +02:00
64647edbe1 lib/fmt/SocketAddressFormatter: new library 2023-09-19 11:22:39 +02:00
b36f5f1ec4 net/ToString: use #pragma once 2023-09-18 22:01:40 +02:00
592649d3f2 net/ToString: check family==AF_INET6 instead of looking for colons 2023-09-18 21:59:27 +02:00
9398599816 net/ToString: use libfmt 2023-09-18 21:58:55 +02:00
61c29473d3 net/ToString: append port only if it is non-zero 2023-09-18 11:11:00 +02:00
5fd2fc77f3 net/ToString: add null check 2023-09-18 11:08:16 +02:00
3eb0681e3d net/ToString: use SocketAddress::GetLocalRaw() 2023-09-18 10:54:52 +02:00
e831af35fd input/curl: move code to CreateEasy() 2023-09-17 14:26:47 +02:00
fb2e0f734e lib/fmt/ToBuffer: add overload with StringBuffer parameter 2023-09-16 23:05:48 +02:00
3d69f43cff event/Loop: include SocketEvent.hxx only if HAVE_THREADED_EVENT_LOOP 2023-09-16 22:55:04 +02:00
41b1931d91 event/Loop: move the poll_backend to the top
This is where all sockets are registered, so it should be initialized
first and destructed last.
2023-09-16 22:45:45 +02:00
f086444e4a lib/curl/Easy: add method SetRequestBody(std::string_view) 2023-09-16 22:39:03 +02:00
b8210bbc45 lib/avahi/Poll: fix copyright header 2023-09-16 22:39:03 +02:00
ce2965b5bc io/uring/meson.build: disable io_uring on Android
On Android, the feature is forbidden by a seccomp filter, see

 https://security.googleblog.com/2023/06/learnings-from-kctf-vrps-42-linux.html
2023-09-16 22:39:03 +02:00
18000ff499 io/uring/Handler: remove unused header 2023-09-16 22:39:03 +02:00
64e91d6eb7 test/util/TestIntrusiveForwardList: add constant_time_size test 2023-09-16 22:39:03 +02:00
6f7dce6dca test/util/TestIntrusiveForwardList: implement size() only if options.constant_time_size is set 2023-09-16 22:39:03 +02:00
175524ad02 util/IntrusiveForwardList: make end() non-static
So we can have a `const` overload which is important for some
algorithm templates.
2023-09-16 22:39:03 +02:00
bfbde72676 util/Intrusive*: insertion methods return an iterator 2023-09-16 22:39:03 +02:00
f76583a08a util/IntrusiveList: document the erase() return value 2023-09-16 22:39:03 +02:00
6d39b401b5 util/IntrusiveForwardList: add method iterator_to() 2023-09-16 22:39:03 +02:00
f448bfd3f3 util/IntrusiveForwardList: add option cache_last 2023-09-16 22:39:03 +02:00
64b0587e78 util/OptionalField: new library 2023-09-16 22:39:03 +02:00
9fe813e572 util/IntrusiveForwardList: add pop_front_and_dispose() 2023-09-16 22:39:03 +02:00
b0da0bbf8b util/IntrusiveForwardList: pop_front() returns reference 2023-09-16 22:39:03 +02:00
5c44082b77 util/IntrusiveForwardList: add non-static insert_after() implementation 2023-09-16 22:39:03 +02:00
df7ed27b78 util/IntrusiveForwardList: fix move operator, really swap counter 2023-09-16 22:39:03 +02:00
bef7ce37d9 RemoteTagCache: use the pop_front() return value 2023-09-16 22:39:03 +02:00
c74cf79e0f Merge pull request from MusicPlayerDaemon/dependabot/github_actions/actions/checkout-4
build(deps): bump actions/checkout from 3 to 4
2023-09-16 21:58:20 +02:00
992488c6c6 doc/plugins.rst: document missing httpd settings 2023-09-16 00:18:03 +03:00
bdfe5e97cd systemd: base "RestrictAddressFamilies" on build options
This allows to not allow `AF_NETLINK` if `smbclient` is not enabled.
2023-09-15 23:39:00 +03:00
df069bc456 systemd: base "ListenStream" on build options
Make `mpd.socket` configurable based on build options, so that e.g.
`ListenStream=6600` is not added if `tcp` option is not enabled.
2023-09-15 23:38:59 +03:00
9bb67ae7f0 subprojects: update sqlite to 3.43.0-1 2023-09-12 10:21:27 +02:00
c994fe4879 io/uring/meson.build: detect liburing with include_type=system
This avoids breakages due to `-Wgnu-anonymous-struct`.
2023-09-12 10:20:58 +02:00
32421fed89 subprojects: update liburing to 2.3-3 2023-09-12 10:17:03 +02:00
077add79cd subprojects: update fmt to 9.1.0-2 2023-09-12 10:16:56 +02:00
50f0163f5f time/SystemClock: pass by value 2023-09-12 09:56:06 +02:00
481c1b6f2e lib/dbus/ReadIter: add method GetBool() 2023-09-12 09:53:58 +02:00
474b6610fa lib/dbus/Error: add method GetName() 2023-09-12 09:53:15 +02:00
11c49da871 io/FileReader: remove unused method Close()
It's enough to have the destructor.
2023-09-12 09:53:06 +02:00
678828b56f io/FileOutputStream: remove obsolete maybe_unused 2023-09-12 09:43:14 +02:00
9e802ad721 util/StringCompare: add pure attribute 2023-09-12 09:34:52 +02:00
859ffddea3 io/BufferedReader: fix ReadFullT() after std::span migration 2023-09-12 09:32:20 +02:00
daf935d310 util/HexFormat: add non-const overload 2023-09-12 09:11:38 +02:00
6953800628 python/build/libs.py: update CURL to 8.2.1 2023-09-11 22:24:27 +02:00
7c65c4f485 python/build/libs.py: update OpenSSL to 3.1.2 2023-09-11 22:23:59 +02:00
8950fb9393 python/build/libs.py: update zlib to 1.3 2023-09-11 22:22:00 +02:00
b754f3dc34 python/build/libs.py: update Opus to 1.4 2023-09-11 22:21:04 +02:00
e8a25dc8d9 python/build/libs.py: update FLAC to 1.4.3 2023-09-11 22:19:41 +02:00
99765cc704 modplug: add patch to remove the deprecated register keyword 2023-09-11 22:17:45 +02:00
a868dbce3b android/AndroidManifest.xml: raise minSdkVersion to 24
This is needed to build libFLAC which uses ftello().
2023-09-11 22:14:23 +02:00
f68305bf00 util/NumberParser: remove obsolete __ANDROID_API__ check 2023-09-11 22:12:13 +02:00
517c234461 lib/zlib/GzipOutputStream: use MAX_WBITS 2023-09-11 22:02:04 +02:00
a58275591d util/StaticVector: add methods erase(), pop_front() 2023-09-11 21:59:28 +02:00
a2f4fb9ddb util/StaticVector: add method pop_back() 2023-09-11 21:59:21 +02:00
b2acf02af9 util/StaticVector: push_back(), emplace_back() return reference
Imitating std::vector since C++17.
2023-09-11 21:59:12 +02:00
d5b1ca1a52 util/StaticVector: use emplace_back() to implement push_back()
For this class, both are equal.
2023-09-11 21:58:56 +02:00
339b9f6e7b net/StaticSocketAddress: add method GetSteadyPart() 2023-09-11 21:27:12 +02:00
35cfa6efa3 net/StaticSocketAddress: add SocketAddress cast constructor 2023-09-11 21:27:12 +02:00
34ec024bf4 net/AllocatedSocketAddress: add method GetSteadyPart() 2023-09-11 21:27:12 +02:00
75aa08ed6b tag/Pool: use a power-of-2 hash table size
This is simpler to calculate and the advantage of using a prime is
negligible anyway.
2023-09-11 21:23:11 +02:00
c8dc1e0665 tag/Pool: use class IntrusiveHashSet intead of rolling a custom hash table 2023-09-11 21:15:28 +02:00
847ae7dd7c util/IntrusiveHashSet: add insert_check_if() 2023-09-11 21:15:28 +02:00
44f55e1866 util/IntrusiveList: add missing initializer to insert_after()
We must not call std::next() if the list head was not yet initialized.
This was missing in commit 7065425927
2023-09-11 21:15:28 +02:00
c391adad10 tag/Pool: move code from calc_hash() to util/djb_hash.cxx 2023-09-11 20:53:37 +02:00
f578b06d83 tag/Pool: move calc_hash() returns std::size_t 2023-09-11 20:51:44 +02:00
0748f75d9b tag/Pool: rename TagPoolSlot to TagPoolItem 2023-09-11 20:44:55 +02:00
7dff29bcd1 util/IntrusiveHashSet: add option zero_initialized 2023-09-11 20:34:17 +02:00
3e09f95b40 tag/Pool: enable option zero_initialized
Commit 44beae519d caused the MPD
executable to grow by more than 1 MB because the `slots` array
suddenly was not zero-initialized anymore, because the doubly-linked
list is circular, while the singly-linked list is zero-terminated.

This option moves the array back to the `bss` section.
2023-09-11 20:32:26 +02:00
7065425927 util/IntrusiveList: add option zero_initialized 2023-09-11 20:30:38 +02:00
f01793ad4a util/Intrusive*: move constant_time_size to an options struct
This makes it easier to add more options later.
2023-09-11 19:18:36 +02:00
1f495efb46 test/LoadDatabase: ignore tag/charset mismatches
This program shouldn't fail just because the configuration doesn't
match - it has no configuration, it's just a dumb test program.
2023-09-07 09:54:03 +02:00
38d8359384 test/LoadDatabase: new test program (for benchmarking the database loader) 2023-09-06 16:17:24 +02:00
2c01e79b47 SongSave: omit FixTagString() for strings from the database file
Strings in the database should have been sanitized already, so let's
not waste CPU on this.
2023-09-06 16:12:20 +02:00
a573d57de8 tag/Builder: remove unnecessary explicit AddItem() overload 2023-09-06 16:10:31 +02:00
2f4e2935a3 db/upnp, playlist/pls: use AddItem(std::string_view) 2023-09-06 16:08:42 +02:00
44beae519d tag/Pool: use doubly-linked list
This adds some memory overhead but eliminates the linear search from
tag_pool_put_item().
2023-09-06 16:00:25 +02:00
b896711fc6 tag/Pool: fix crash in tag_pool_put_item()
Regression by commit 76bdfabcc5
2023-09-06 15:53:17 +02:00
76bdfabcc5 tag/Pool: use class IntrusiveForwardList 2023-09-06 15:33:26 +02:00
b35e8a588f util/IntrusiveForwardList: add operator++(int) 2023-09-06 15:31:07 +02:00
6c48f5ac63 tag/Pool: use std::array 2023-09-06 15:10:47 +02:00
1448f52eac util/VarSize: convert static_assert to concept check 2023-09-06 15:05:26 +02:00
c96e8ab47c db/simple/DirectorySave: optimize duplicate checks with std::set
This reduces the CPU usage for loading a large database by more than 50%.
2023-09-06 14:56:41 +02:00
2c4ef4460f db/update/SpecialDirectory: more std::string_view migration 2023-09-06 14:51:37 +02:00
20bbe1b57b fs/Traits: add GetFilenameSuffix() overload with std::string_view 2023-09-06 14:50:36 +02:00
449d59af2f db/simple/Directory: use operator== to compare strings 2023-09-06 14:30:08 +02:00
851136e6fd db/simple/Directory: GetName() returns std::string_view 2023-09-06 14:29:32 +02:00
ad854e9867 db/simple/Save: initialize array without memset() 2023-09-06 14:17:07 +02:00
f53dde970f build(deps): bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 15:51:28 +00:00
046a385070 doc/user.rst: use explicit meson setup command
The implicit setup command is deprecated since 0.64.0
2023-08-24 13:57:03 +03:00
9a28176d72 Save consume and single oneshot as string
Consume and single oneshot should be saved as string.

closes 
2023-08-07 23:23:08 +02:00
ba2df05fb4 lib/zlib/GzipOutputStream: add noexcept 2023-08-03 20:58:43 +02:00
8722c51306 lib/dbus/AppendIter: add Append(int32_t), Append(int64_t) 2023-08-03 20:58:01 +02:00
80104eb6d5 util/IntrusiveList: fix illegal downcast (ubsan)
Fixes UBSanitizer warning:

 src/util/IntrusiveList.hxx:108:10: runtime error: downcast of address 0xdeadbeef which does not point to an object of type 'Foo'
2023-08-03 20:56:34 +02:00
8743326924 sticker/Database: allow moving 2023-08-03 20:54:57 +02:00
83a6cb804b util/IntrusiveHashSet: add template argument GetKey
This is a big simplification of all IntrusiveHashSet users: instead of
having to implement multiple overloads of Hash and Equal, the
IntrusiveHashSet class can first extract the effective key from an
item and then pass it to the Hash/Equal functions.
2023-08-03 20:50:21 +02:00
78801f303e test/util/TestIntrusiveHashSet: add test for remove_and_dispose_key() 2023-08-03 20:44:52 +02:00
9691b609a2 util/IntrusiveHashSet: remove_and_dispose() returns number of removed elements 2023-08-03 20:44:47 +02:00
250fa8c732 util/IntrusiveHashSet: rename remove_and_dispose() to remove_and_dispose_key() 2023-08-03 20:44:39 +02:00
2cd5f4cd3e util/IntrusiveHashSet: replace template parameters Hash/Equal with a single one
Preparing to add a key extraction function.  Without this "Operators"
template parameter, we'd have even more template parameters, and that
parameter list would grow too complex.  Better wrap it in one single
template that contains all operators.

This is an API change which all callers need to adjust to, but it will
be worth it.
2023-08-03 20:44:14 +02:00
dcd7c6337c util/Intrusive{List,HashSet}: reimplement hook mode detection with implicit cast 2023-08-03 20:33:15 +02:00
43d633f560 Instance: use C++11 initializers 2023-07-23 09:14:25 +02:00
1c37b0487c lib/fmt/SystemError: add VFmtErrno() 2023-07-21 19:44:45 +02:00
acc92b156b util/Concepts: remove obsolete fallbacks 2023-07-21 19:43:04 +02:00
aeadae5399 util/IntrusiveHashSet: insert_check() returns the bucket head on success
The list head is a stable value that is guaranteed to be still valid
when insert_commit() gets called.

This fixes a linked list corruption bug in class StaticCache which
occurs when the cache item pointed to by the iterator gets evicted
between insert_check() and insert_commit().
2023-07-21 19:42:35 +02:00
42d5b05f54 util/IntrusiveHashSet: rename insert() to insert_commit()
Clarify that the method is not a freestanding insertion method but
should only be used after insert_check().
2023-07-21 19:42:26 +02:00
e133f621a4 util/IntrusiveHashSet: add insert_check() documentation 2023-07-21 19:41:46 +02:00
91437d9e63 util/IntrusiveList: add insert_after() 2023-07-21 19:41:40 +02:00
f1b497fb0c util/IntrusiveList: document insert() 2023-07-21 19:41:36 +02:00
cc9d061e51 util/IntrusiveList: pop_front() and pop_back() return reference 2023-07-21 19:41:13 +02:00
62ee9a4d60 util/DynamicFifoBuffer: use T instead of std::byte
Mistake added by commit b528b467649754
2023-07-21 19:40:38 +02:00
082f72dd20 Add support of TAG_MUSICBRAINZ_RELEASEGROUPID
Closes 
2023-07-12 19:43:37 +02:00
9c19368fc7 Merge branch 'v0.23.x' 2023-06-02 14:36:02 +02:00
45f81cde6d Merge branch 'null-always-off' of https://github.com/nomis/MPD 2023-05-25 10:42:58 +02:00
a482c798ad pcm: declare IsSilentSample as const
GNU libstdc++ declares cmath functions as constexpr, but libc++ does
not. The C++ standards state the standard library functions should not
be declared constexpr unless explicitly required.
2023-05-24 15:05:19 -04:00
838af929a0 meson: use correct prefix for systemd dirs
See https://www.bassi.io/articles/2018/03/15/pkg-config-and-paths/

Fixes the build in nixpkgs
2023-05-22 22:23:38 +02:00
d9b1f6223e io/uring/Close: wrapper for io_uring_prep_close() 2023-05-22 21:59:44 +02:00
26577d1301 io/uring/Queue: make Submit() virtual, Push() not
This allows submitting io_uring calls without an `Operation` instance
(fire & forget).  We'll do that for close().
2023-05-22 21:57:18 +02:00
6496c1b806 util/ScopeExit: convert the function from base class to member
This allows using `final` callables.
2023-05-22 21:20:49 +02:00
7bb251dad8 db/update/Walk: use marker to remove deleted items
This eliminates all `Storage::GetInfo()` calls from
`UpdateWalk::PurgeDeletedFromDirectory()` and instead uses a "marker"
field to mark items that have been visited; later, all unmarked items
can be deleted.

This eliminates a lot of redundant I/O which is noticable with the
`curl` storage plugin (i.e. WebDAV).
2023-05-22 20:13:01 +02:00
9027e5c5bb Merge tag 'v0.23.13'
release v0.23.13
2023-05-22 19:52:08 +02:00
8ba68fdb47 io/OutputStream: use std::span 2023-05-21 21:35:11 +02:00
e72d27566c io/BufferedOutputStream: use std::string_view 2023-05-21 21:31:32 +02:00
01c02a1ef8 util/StaticFifoBuffer: add method MoveFrom() 2023-05-21 21:26:20 +02:00
4bb4611e78 Merge branch 'v0.23.x' 2023-05-21 21:18:45 +02:00
c69b9780df Merge branch 'reorder-decoder-plugins' of https://github.com/fuck-shithub/MPD 2023-05-15 21:03:35 +02:00
f869593ac8 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-15 21:00:24 +02:00
181b96dd2d 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-15 20:59:05 +02:00
4e9f463bb6 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-12 00:28:56 +02:00
4947bb113d input/plugins/Alsa: limit ALSA buffer time to 2 seconds maximum
Some ALSA capture devices can have very large buffers, holding 10
seconds or more audio. Using the maximum buffer size with such
devices leads to unacceptably large, and unnecessary, latency.
Also, some ALSA drivers (e.g. HDA Intel PCH) report an invalid
maximum period size, and the period size that mpd calculates from
the maximum buffer size results in "Invalid argument" error when
applying the hw_params. Note that the "default" capture device on
many cards includes the "dsnoop" plugin which imposes a buffer
size of 16384 frames, so that "alsa://" works OK but
"alsa://plughw" or "alsa://hw" both fail.

Limit the maximum buffer time for ALSA input devices to a more useable
2 seconds, thereby avoiding both the above problems.
2023-05-06 10:33:48 +01:00
4345a656aa output/httpd: fix libfmt icy-metaint replacement field
Since using libfmt (commit: dfc5b49) ICY MetaData was broken. Eg MP3 streams encoded with LAME were affected resulting in missing stream titles on VLC or strange noises on Sonos hardware. This commit fixes the icy-metaint field.
2023-05-04 18:15:13 +02:00
31dc8b73b7 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-04-30 08:46:52 +02:00
e84db4f411 db/update/Archive: ignore filenames with newline character 2023-04-30 08:45:34 +02:00
395bf34a91 db/update/Archive: move check to IsAcceptableFilename() 2023-04-30 08:42:16 +02:00
dcc7628b67 db/update/Archive: remove useless log message 2023-04-30 08:39:34 +02:00
f2a4ae15aa db/update: pass filenames as std::string_view 2023-04-30 08:28:43 +02:00
434bcb08ee db/simple/Song: pass std::string_view to Load{File,FromArchive}() 2023-04-30 08:21:20 +02:00
99885c4cbc util/IntrusiveHashSet: add method remove_and_dispose() 2023-04-22 08:40:53 +02:00
ab196f7afc output/Control: Support always_off outputs that are never used for playback
Add an `always_off` option to outputs that causes them to never start
playback even if they're enabled.

This allows placeholder `null` outputs to be defined for the purpose
of having an external client react to the enabled state without the
side effects of real outputs. Like an external mixer, the client can
perform some action when an output is enabled.

Normally `null` outputs can be used for playback so it's possible for
MPD to continue playback silently if a problem occurs with all the real
outputs (or there are none enabled).
2023-04-21 20:54:37 +01:00
90c3fe22f5 decoder/openmpt: check libopenmpt version at compile time, not at configure time 2023-04-21 17:29:20 +02:00
ad8117e7c8 decoder/openmpt: Fix build error with libopenmpt < 0.5
openmpt_at_end is a string, not an integer

Fixes build error:

 src/decoder/plugins/OpenmptDecoderPlugin.cxx: In function 'void mod_decode(DecoderClient&, InputStream&)':
 src/decoder/plugins/OpenmptDecoderPlugin.cxx:85:44: error: invalid cast from type 'std::string_view' {aka 'std::basic_string_view<char>'} to type 'unsigned in '
   85 |  mod.ctl_set("play.at_end", std::to_string((unsigned)openmpt_at_end));
      |                                            ^~~~~~~~~~~~~~~~~~~~~~~~
2023-04-21 17:24:42 +02:00
82568c0b52 Fix syntax error in mpdconf.example 2023-04-13 08:47:43 +02:00
838b19c2b5 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-04-12 05:18:21 +02:00
0d2f67b523 check systemd unit dir from systemd.pc in meson 2023-04-11 21:06:53 +02:00
a57bcd0238 thread/Mutex: add RecursiveMutex 2023-04-06 21:32:18 +02:00
76497bd5f7 util/IntrusiveSortedList, event/TimerList: include cleanup 2023-04-06 10:24:53 +02:00
53ec02d5e9 net/SocketDescriptor: decouple from FileDescriptor on Windows
On Windows, a socket is not a file descriptor; it is a different beast
(and anyway, Windows doesn't have file descriptors).
2023-03-29 10:12:50 +02:00
7a5f485cf8 event/ServerSocket: use class UniqueSocketDescriptor in SupportsIPv6() 2023-03-29 10:06:48 +02:00
90565b1e36 test/run_{input,output}: add missing includes 2023-03-29 10:06:48 +02:00
6f7c7a2149 event/EpollBackend: add missing header guard 2023-03-21 11:00:41 +01:00
91123983ad Revert "python/build/meson.py: keep Meson from executing Android-x86 test binaries"
This reverts commit 8ab2722300.  The
"needs_exe_wrapper" setting was already there, and the new one was
misplaced, it belongs in "[properties]".
2023-03-21 09:46:25 +01:00
2506edbffb python/build/libs.py: update OpenSSL to 3.1.0 2023-03-21 09:39:28 +01:00
929520ecd2 python/build/libs.py: update CURL to 8.0.1 2023-03-21 09:38:22 +01:00
a20d467bf1 event/Loop: move quit_injected check to inside #ifdef HAVE_THREADED_EVENT_LOOP 2023-03-20 15:02:32 +01:00
102dc123e8 LogBackend: log to stderr (regression fix) 2023-03-14 20:25:28 +01:00
b4d0b23369 LogBackend: use fmt::print() 2023-03-14 20:24:14 +01:00
119a949bb5 ls: use fmt::print() 2023-03-14 20:20:46 +01:00
f5b22bf2c3 input/Offset: remove unused macro PRIoffset 2023-03-14 20:20:10 +01:00
5b7a89d714 mixer/plugins/volume_mapping: convert to C++ 2023-03-14 20:18:41 +01:00
5b41857a22 mixer/plugins/volume_mapping: add SPDX header 2023-03-14 20:08:43 +01:00
688d9ff114 util/UriExtract: add uri_get_path_query_fragment()
Rename uri_get_path() to uri_get_path_query_fragment() and add a new
uri_get_path() function.
2023-03-14 20:03:17 +01:00
c2d202e9b0 meson_options.txt: add option "libfuzzer"
This option allows disabling libFuzzer, which is required to run the
fuzzers with Honggfuzz.
2023-03-14 19:47:22 +01:00
bc51bc2933 pcm/Normalizer: add method Reset() 2023-03-13 13:54:12 +01:00
f547a56b1d pcm/Normalizer: use Traits::long_type 2023-03-13 13:51:27 +01:00
1f6637d49a pcm/Normalizer: add constant SHIFT 2023-03-13 13:49:25 +01:00
de155a740c pcm/Normalizer: convert peakPos to std::size_t 2023-03-13 13:47:04 +01:00
f323fc48d7 pcm/Normalizer: eliminate the local variable slot 2023-03-13 13:45:28 +01:00
2ea634c302 pcm/Normalizer: replace the gain array with a simple prev_gain variable 2023-03-13 13:44:45 +01:00
c0d38d941a pcm/Normalizer: split the normalization loop
Performance improvement because the ramp code is now moved out of the
hot code path, allowing the compiler to vectorize.
2023-03-13 13:38:19 +01:00
d7f2d90fd3 pcm/Normalizer: no in-place editing, separate src/dest parameters
This eliminates the memcpy() call from NormalizeFilter::FilterPCM().
2023-03-13 13:37:49 +01:00
8ea9b89321 pcm/Normalizer: use std::span 2023-03-13 13:16:44 +01:00
738254b2fc pcm/Normalizer: use SampleTraits 2023-03-13 12:42:37 +01:00
fcc9a98cad pcm/Normalizer: use PcmClamp() 2023-03-13 12:42:36 +01:00
dcf0a3e475 pcm/Normalizer: remove clipped (only written to, never read) 2023-03-13 12:42:34 +01:00
e990d6eecc pcm/Normalizer: make variables more local 2023-03-13 12:42:31 +01:00
941636b87b pcm/Normalizer: eliminate local variable ap 2023-03-13 12:31:16 +01:00
1298a82f4f pcm/Normalizer: use std::size_t 2023-03-13 12:31:16 +01:00
e6fedcbd10 pcm/Normalizer: expose the class, convert functions to methods 2023-03-13 12:25:09 +01:00
48c8c7daf5 pcm/Normalizer: move code to ctor/dtor 2023-03-13 12:25:09 +01:00
6e5d9d4490 pcm/Normalizer: hard-code the preferences 2023-03-13 12:25:09 +01:00
d2f2dde2e1 pcm/Normalizer: eliminate struct CompressorConfig 2023-03-13 12:25:09 +01:00
d0dd035075 pcm/Normalizer: use new/delete instead of malloc()/free() 2023-03-13 12:25:09 +01:00
7702643e1b pcm/Normalizer: remove Compressor_setHistory(), no resize possible
This feature was never used.
2023-03-13 12:25:09 +01:00
984c9c317a pcm/Normalizer: add noexcept 2023-03-13 12:25:09 +01:00
2d7068a09d pcm/AudioCompress: convert to C++ 2023-03-13 12:25:01 +01:00
d712c3b408 pcm/AudioCompress: fold config.h into compress.c 2023-03-13 11:55:44 +01:00
0a623122dc pcm/AudioCompress: add SPDX header 2023-03-13 11:40:46 +01:00
68c36c0d3f decoder/dsf: use PackedLE64 instead of DsdUint64 2023-03-12 20:27:05 +01:00
f3ebaf8bdd util/ByteOrder: add class PackedLE64 2023-03-12 20:25:49 +01:00
c472046cbb decoder/dsdiff: use PackedBE64 instead of DffDsdUint64 2023-03-12 20:22:50 +01:00
02296adbba io/FileDescriptor: include cleanup 2023-03-12 20:18:13 +01:00
a375f0f160 io/BufferedReader: add method ReadFullT() 2023-03-12 20:15:41 +01:00
fb961e89da util/StringCompare: add constexpr 2023-03-12 20:14:23 +01:00
3e2bff296f event/SocketEvent: add method GetReadyFlags() 2023-03-12 20:12:15 +01:00
cf01db4d08 event/Chrono, ...: relicense to BSD-2 2023-03-12 20:02:54 +01:00
08dbb4a69a event/BackendEvents: relicense to BSD-2
These headers contain only trivial integer constants and these are
probably not even copyrightable.
2023-03-12 19:53:03 +01:00
b5eff3cecd decoder/plugin: kludge for Android NDK r25c 2023-03-12 19:53:03 +01:00
89d66b6100 decoder/ffmpeg: check for DST codec
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1756
2023-03-12 19:39:49 +01:00
c53ee41855 decoder/ffmpeg: check for DSD codec
DSD uses a generic demuxer, therefore it does not appear in the
demuxer list.
2023-03-12 19:37:09 +01:00
3c798b4907 decoder/ffmpeg: query supported demuxers at runtime 2023-03-12 19:37:09 +01:00
78a9c17bc6 decoder/plugin: add "suffixes" function
For decoder plugins like FFmpeg where the supported codecs cannot be
determined at compile time.
2023-03-12 09:17:38 +01:00
8b77da545d *: use transparent comparison for std::{map,set} with std::string keys
This avoids many std::string temporaries for lookups.
2023-03-12 09:12:02 +01:00
27d3dcf14c CommandLine: use libfmt 2023-03-12 09:02:21 +01:00
5388759bd5 db/proxy: require libmpdclient 2.15 or later 2023-03-10 13:45:37 +01:00
e927655774 db/proxy: require MPD 0.21 or later 2023-03-10 13:43:49 +01:00
3be8375e4f subprojects/sqlite3.wrap: update to 3.41.0-1 2023-03-10 13:35:01 +01:00
27ba8c181f pcm/SoxrResampler: require libsoxr 0.1.2 or later 2023-03-10 12:49:57 +01:00
1410bcbce9 lib/alsa: require alsa-lib 1.1 or later 2023-03-10 12:49:40 +01:00
43b26ee612 {de,en}coder/flac: remove obsolete FLAC_API_VERSION_CURRENT checks
We check the libFLAC version via pkg-config at configure time, no need
to do it again.
2023-03-10 12:43:19 +01:00
2c47357991 python/build/libs.py: update WildMidi to 0.4.5 2023-03-09 18:33:21 +01:00
7e2538e07a decoder/sidplay: require libsidplayfp (drop support for the original sidplay)
The original sidplay project has been mostly unmaintained for nearly
12 years, and the most recent release was in 2016, while the
libsidplayfp project has been actively maintained all the time.
2023-03-09 18:27:05 +01:00
851fcf4823 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-03-09 18:27:05 +01:00
63b9fb3d2b event/meson.build: add missing dependency on libio.a 2023-03-09 18:27:05 +01:00
a79454f6a6 io/FileDescriptor: fold CreateSignalFD() into the SignalFD constructor 2023-03-09 18:04:58 +01:00
b5fbfe9aa6 io/FileDescriptor: fold CreateEventFD() into the EventFD constructor 2023-03-09 17:59:56 +01:00
598894211f decoder/ffmpeg: require FFmpeg 4.0 or later 2023-03-08 20:32:35 +01:00
dbfd0a833d io/meson.build: move sources to libio_fs.a
Only that one has a dependency on libfs.a (for class AllocatedPath
etc.).
2023-03-07 12:48:47 +01:00
d45994268f system/PeriodClock: move to time/ 2023-03-07 12:08:44 +01:00
815b248990 */Registry: use constinit 2023-03-07 12:04:16 +01:00
333b36f090 output/Registry: add noexcept 2023-03-07 11:57:55 +01:00
b18ef61361 output/Registry: rename function 2023-03-07 11:57:36 +01:00
86ae45108c output/Finish: fold into Filtered.cxx 2023-03-07 11:54:46 +01:00
5ef29c424d output/meson.build: add liboutput_registry.a 2023-03-07 11:53:16 +01:00
c8dfb57408 output/meson.build: move OutputPlugin.cxx to liboutput_api.a 2023-03-07 11:52:32 +01:00
b773ef3f0f win32/HResult: use libfmt 2023-03-06 20:10:06 +01:00
c8f54b3509 lib/pcre/UniqueRegex: use libfmt 2023-03-06 20:10:06 +01:00
00d5e6e9c7 lib/avahi/Publisher: use libfmt 2023-03-06 20:10:06 +01:00
1132a1c9a7 protocol/ArgParser: use libfmt 2023-03-06 20:10:06 +01:00
149d1a2f47 output/shout: use libfmt 2023-03-06 20:10:06 +01:00
17f2c0ae88 output/httpd: use libfmt 2023-03-06 20:10:06 +01:00
ce0b4d5c19 system/Error: remove unused function FormatSystemError() 2023-03-06 20:10:06 +01:00
0c102a8f2f meson.build: add missing libfmt dependencies 2023-03-06 20:10:06 +01:00
415de497d3 use more libfmt instead of sprintf() 2023-03-06 19:50:53 +01:00
02d108774c test/meson.build: add missing dependencies on libio.a 2023-03-06 19:50:52 +01:00
2c66d90626 fs/io: move to separate library
To eliminate the libio.a dependency.
2023-03-06 19:47:29 +01:00
e4cdf29951 fs/meson.build: make several dependencies internal 2023-03-06 19:44:34 +01:00
b5d224ce22 fs/{StandardDirectory,CheckFile}: move to fs/glue/
Distangle library dependencies.
2023-03-06 19:43:09 +01:00
c937a299f7 fs/Charset: assign fs_charset
This got lost 8 years ago in commit 87c88fcb27

D'oh!
2023-03-06 19:25:44 +01:00
6d4ec8b46f fs/Charset: remove useless log message 2023-03-06 19:20:22 +01:00
941f2ca60d pcm/{Traits,Dsd*}: use std::byte 2023-03-06 18:44:20 +01:00
7a1b996da9 pcm/Dsd2Pcm: use SampleTraits<SampleFormat::DSD>::SILENCE 2023-03-06 18:30:16 +01:00
302a571367 pcm/Buffer: use std::byte 2023-03-06 18:22:12 +01:00
ec195acf4f pcm/Interleave: use std::byte 2023-03-06 18:22:10 +01:00
8f41e05a39 db/upnp/ContentDirectoryService: use fmt::format_int 2023-03-06 16:45:59 +01:00
35b6d65f27 util/Compiler.h: remove unused compiler version check macros 2023-03-06 16:37:46 +01:00
e602bcf41e pcm/ReplayGainAnalyzer: remove GCC version checks, assume proper C++17 support 2023-03-06 16:37:45 +01:00
8c5ba50840 command/{file,storage}: remove stray "#pragma GCC diagnostic pop" 2023-03-06 16:37:45 +01:00
ff239fff4f util/ByteOrder: check only __GNUC__
Assume GCC/clang is recent enough.
2023-03-06 16:37:45 +01:00
abdbaf605e player/Thread, ...: assume [[fallthrough]] is supported 2023-03-06 16:29:55 +01:00
47b3577d6b util/Compiler.h: remove unused macro gcc_printf 2023-03-06 16:27:47 +01:00
2ffc7c2088 io/BufferedOutputStream: remove unused method Format() 2023-03-06 16:27:28 +01:00
1f56960c44 util/FormatString: remove unused library 2023-03-06 16:24:51 +01:00
dfc5b4972b output/httpd/IcyMetaDataServer: use libfmt 2023-03-06 16:23:43 +01:00
18c3c2118d util/Compiler.h: remove unused macros 2023-03-06 16:14:30 +01:00
42f6a0441c use [[gnu::...]] attributes 2023-03-06 16:14:15 +01:00
3b9aab0684 util/UTF8: fix indent 2023-03-06 16:12:09 +01:00
7a46c57ef3 tag/Type: require C++ 2023-03-06 15:28:44 +01:00
118b76a8f1 db/Interface, ...: forward-declare TagType 2023-03-06 15:25:30 +01:00
a302d34f6d tag/Names: convert to C++ 2023-03-06 15:16:33 +01:00
148aca23be use SPDX IDs, replacing the long copyright headers 2023-03-06 14:59:48 +01:00
8ab2722300 python/build/meson.py: keep Meson from executing Android-x86 test binaries 2023-03-06 14:21:37 +01:00
bd25528ca3 python/build/meson.py: remove unused import 2023-03-06 14:17:44 +01:00
9f02d8978b 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-03-06 14:15:57 +01:00
7e51d1dba0 build/python/cmake: set CMAKE_OSX_SYSROOT on macOS 2023-03-06 14:15:23 +01:00
4d4755352d build/python/cmake: add "env" parameter 2023-03-06 14:13:08 +01:00
0360f79e6f build/python/build/project.py: add "lazy" parameter to make_build_path() 2023-03-06 14:10:10 +01:00
6d8f92c185 build/python/build/project.py: raise exception on regex mismatch 2023-03-06 14:07:59 +01:00
c989327eb0 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-03-06 13:48:40 +01:00
22eccaa64f python/build/autotools.py: use toolchain.arflags 2023-03-06 13:33:11 +01:00
740cc8ce49 python/{cmake,autotools}: build in verbose mode
Make sure all the gory details are visible in CI logs.
2023-03-06 13:32:48 +01:00
70eafba0d4 python/build/autotools.py: dump config.log on configure error
For better error logs on CI.
2023-03-06 13:32:42 +01:00
79fb9834d9 python/makeproject: do not use hard-code absolute path to make 2023-03-06 13:32:37 +01:00
146db77025 python/makeproject: set appropriate build jobs count depending on the number of CPUs 2023-03-06 13:32:32 +01:00
e6d607fef3 build/python: do not use absolute path for tar 2023-03-06 13:10:03 +01:00
ca46992d3e build/python/build/project.py: lazy tarball extraction 2023-03-06 13:07:17 +01:00
c83ab0dc58 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-03-06 13:00:07 +01:00
d9952b9054 CommandLine: hard-code daemon=false if ENABLE_DAEMON is not set 2023-03-06 13:00:06 +01:00
04e60d67ae command/playlist: allow range in "playlistmove"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1689
2023-03-06 12:01:45 +01:00
f4adbdbe31 python/build/libs.py: update FFmpeg to 6.0 2023-03-06 10:13:12 +01:00
484b820dfc python/build/libs.py: disable more unused FFmpeg features 2023-03-06 10:06:39 +01:00
9bcba41cd6 Merge branch 'pipewire-lock' of https://github.com/ncfavier/MPD
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1753
2023-03-06 10:06:03 +01:00
eabc487e59 output/PipeWire: lock thread loop in SendTag 2023-03-06 10:03:14 +01:00
5c5e522fcd output/jack: remove DLL support
This effectively reverts commit 0f02bbc2fe which was a horrible
kludge for JACK support on Windows.  Maintaining this kludge doesn't
seem worth the trouble (the JACK version was never updated), and
apparently nobody uses this.
2023-03-06 08:10:00 +01:00
f687028c87 output/PipeWire: use class StaticVector 2023-03-06 08:09:07 +01:00
05f0b9c29c python/build/libs.py: update CURL to 7.88.1 2023-03-06 07:56:08 +01:00
4a8ec20858 python/build/libs.py: update OpenSSL to 3.0.8 2023-03-06 07:56:08 +01:00
c5e36a7dd8 subprojects: update expat to 2.5.0-2 2023-03-06 07:51:02 +01:00
d5fafa1340 output/PipeWire: map tags "Date" and "Comment" 2023-03-06 07:48:25 +01:00
e8994b43a0 output/PipeWire: convert tag mapping to array 2023-03-06 07:44:06 +01:00
6ada2c9c3f lib/curl/Request: add method GetEasy() 2023-03-05 08:50:39 +01:00
bbf190fc42 lib/curl/Multi: add noexcept 2023-03-05 08:49:20 +01:00
963ff1997d lib/curl/Easy: add methods SetXferInfoFunction(), SetMimePost() 2023-03-05 08:47:40 +01:00
5c2a576546 io/BufferedReader: add missing include 2023-03-05 08:43:41 +01:00
452400b7ef net/SocketAddress: remove __cpp_lib_span checks 2023-03-05 08:41:33 +01:00
20a5276560 doc/mpd.1.rst: add documentation for --systemd
This switch was introduced in ce77b148d9
2023-03-01 09:55:27 +01:00
c94eee6199 Merge branch 'master' of https://github.com/lerenwe/MPD-Windows-With-Libsample 2023-02-23 14:44:06 +01:00
2a75222fe2 Added libsamplerate to win32 build script 2023-02-23 14:26:32 +01:00
7d9d173c9f Updated libs.py to integrate libsamplerate 0.2.2 2023-02-23 14:25:11 +01:00
f248fe2dec Resolve deprecation warnings by replacing use of sprintf with FmtBuffer 2023-02-06 11:56:49 +01:00
e0df0b6d74 oss: Remove use of the soundcard.h header, OpenBSD no longer uses OSS 2023-02-03 18:38:20 -05:00
a41414e0e0 Decoder/FluidSynth: Allow gain to be adjusted 2023-02-01 12:00:19 -05:00
f1cea1f152 util/IntrusiveHashSet: add unlink(), is_linked() 2023-01-31 13:07:26 +01:00
02f5698868 event/Loop: remove unnecessary include
Not used since a3b32819b1
2023-01-31 13:04:25 +01:00
e25816fc05 Provide alternative ways to check for
https://superuser.com/questions/287371/obtain-kernel-config-from-currently-running-linux-system/287372#287372
2023-01-31 08:21:39 +00:00
5b07c8fc6c util/CharUtil: add IsLowerAlphaNumericASCII() 2023-01-29 09:39:40 +01:00
b45afd1cab util/StringBuffer: add constexpr 2023-01-29 09:38:40 +01:00
8b73257a86 storage/meson.build: move MemoryDirectoryReader.cxx to storage_api.a
This library is required by the plugins, so this fixes a dependency issue.
2023-01-29 08:21:58 +01:00
def6fffcf1 event/Loop: fixup for NO_FINE_TIMER_EVENT 2023-01-29 08:07:03 +01:00
78b13577ef test/net/TestIPv[46]Address: add more tests 2023-01-28 08:15:41 +01:00
1f5d50ccce lib/curl/Setup: include cleanup 2023-01-28 08:06:10 +01:00
ebf65572dd util/ByteOrder: remove unnecessary operator=
The compiler can just use the uint32_t constructor instead.  This was
redundant code.
2023-01-28 07:48:03 +01:00
c30c293d6f 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-01-28 07:44:59 +01:00
9ee1be6fba command/database: add missing include for UINT_MAX 2023-01-23 15:50:49 +01:00
76177dbc79 win32/HResult: use [[gnu::const]] 2023-01-23 15:35:36 +01:00
6cc532c9a0 win32/HResult: remove unused function FormatHResultError() 2023-01-23 15:35:36 +01:00
3cc770a00b remove obsolete Boost dependency
Boost makes building a piece of software much more difficult than
necessary.  It's a huge library, and just uncompressing it takes a
considerable amount of time. MPD only used a tiny fraction of it, yet
its header bloat made the MPD build very slow.  Locating Boost was
difficult due to its arcane build system and its resistance to use
pkg-config; it's always a special case.  MPD could never use features
of newer Boost versions because Linux distributions always shipped old
Boost versions.  Boost made everything complicated and slow.

So, finally, after getting rid of GLib (commit ccdb94b06c), switching
to C++ and using Boost (commit 0801b3f495), we've finally get rid of
it 8 years later.

Unfortunately, I had to reimplement parts of it along the way
(e.g. IntrusiveList).  Kind of NIH, but on the other hand, compiling
MPD has become much easier for users.
2023-01-23 15:06:58 +01:00
7ef0bfbdf1 event/meson.build: disable Boost 2023-01-23 14:58:38 +01:00
bafde1900b lib/nfs/Manager: use IntrusiveList instead of boost::intrusive::set
MPD usually has only one NFS connection, maybe two, so managing them
in a tree seems like overkill, and since we want to get rid of Boost
anyway...
2023-01-23 14:58:09 +01:00
5844242cfb input/cache/Manager: use IntrusiveHashSet instead of boost::intrusive::set 2023-01-23 14:19:22 +01:00
7e7cdf73b9 input/InputStream: add method GetUriView() 2023-01-23 14:15:18 +01:00
5ca74acd8d input/InputStream: allow emplacing the URI 2023-01-23 14:15:18 +01:00
cd2aaac0c2 output/osx: fix typo 2023-01-23 14:15:18 +01:00
ff8a7225fc output/osx: change type to std::size_t to fix -Wc++11-narrowing 2023-01-23 14:06:56 +01:00
c6eac285ea test/util/TestRingBuffer: add "U" literal suffix to work around -Wsign-compare 2023-01-23 14:05:55 +01:00
d0be122fc6 output/osx: use class RingBuffer instead of boost::lockfree::spsc_queue 2023-01-23 13:55:50 +01:00
01e5a7b1b5 output/wasapi: use class RingBuffer instead of boost::lockfree::spsc_queue 2023-01-23 13:44:54 +01:00
0b42018377 output/PipeWire: use class RingBuffer instead of boost::lockfree::spsc_queue 2023-01-23 13:44:54 +01:00
7cb6c70bc2 output/alsa: use class RingBuffer instead of boost::lockfree::spsc_queue 2023-01-23 13:44:54 +01:00
f31ae7c556 util/RingBuffer: replacement for boost::lockfree::spsc_queue 2023-01-23 13:44:54 +01:00
5728c514d1 output/wasapi: use std::hardware_destructive_interference_size 2023-01-23 13:44:53 +01:00
debac0dfd4 win32/ComWorker: use std::queue/Mutex/Cond instead of boost::lockfree::spsc_queue/WinEvent 2023-01-23 13:25:07 +01:00
80b1f49af7 lib/dbus/AppendIter: add missing include 2023-01-22 12:29:54 +01:00
868958e159 util/IntrusiveHashSet: fix find_if() concept 2023-01-22 12:25:55 +01:00
52af03a5a6 util/IntrusiveHashSet: implement remove_and_dispose_if() with constant_time_size 2023-01-22 12:24:50 +01:00
7475e971bc util/IntrusiveList: remove_and_dispose_if() returns the number of removed items 2023-01-22 12:24:43 +01:00
c65b1fee8d util/IntrusiveHashSet: check key equivalence in remove_and_dispose_if() 2023-01-22 12:24:41 +01:00
e2abade6aa util/IntrusiveList: add postfix operator++ 2023-01-22 12:24:33 +01:00
57673136d8 util/IntrusiveHashSet: add method expire_find_if() 2023-01-22 12:24:30 +01:00
49e122a81d util/IntrusiveHashSet: add method remove_and_dispose_if(key) 2023-01-22 12:24:23 +01:00
74976d3199 event: make FineTimerEvent optional
Several applications don't need it, so let's eliminate the code from
the executable.
2023-01-22 12:21:46 +01:00
a750e4afa7 event/Loop: move code to GetEarlierTimeout() 2023-01-22 12:19:07 +01:00
c122e990a3 Merge branch 'master' of https://github.com/faceless2/MPD 2023-01-17 19:03:49 +01:00
b1422fbda4 Merge tag 'v0.23.12'
release v0.23.12
2023-01-17 18:58:04 +01:00
b96e44b362 Unlike album, artist and albumartist, title and composer were not used as a fallback
when titlesort and composersort were specified but unavailable - this patch fixes that.
2023-01-09 18:15:44 +00:00
8a7b7dffec Merge branch 'v0.23.x' 2023-01-06 08:12:38 +01:00
7774e78864 openmpt: add at_end option 2023-01-06 03:18:36 +01:00
d7de8b1453 Merge branch 'iss-1546' of https://github.com/sp1ff/MPD 2022-12-29 08:37:25 +01:00
3242943cd1 doc/protocol.rst: fix reference target 2022-12-18 08:30:25 +01:00
6adff85fd6 Added "searchcount" command, a case-insensitive "count"
The `count` command isn't case-insensitive.  This adds `searchcount`
which is a case-insensitive version of `count`.
2022-12-18 08:29:14 +01:00
8b1ff3f005 build: harden build.yml permissions
This PR adds explicit [permissions section](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions) to workflows. This is a security best practice because by default workflows run with [extended set of permissions](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) (except from `on: pull_request` [from external forks](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)). By specifying any permission explicitly all others are set to none. By using the principle of least privilege the damage a compromised workflow can do (because of an [injection](https://securitylab.github.com/research/github-actions-untrusted-input/) or compromised third party tool or action) is restricted.
It is recommended to have [most strict permissions on the top level](https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions) and grant write permissions on [job level](https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs) case by case.

Signed-off-by: Alex <aleksandrosansan@gmail.com>
2022-12-09 11:28:26 +01:00
756621c6e4 neighbor/meson.build: add missing dependency on libfmt 2022-12-01 15:57:28 +01:00
7e2ab1fd53 lib/yajl/meson.build: add missing dependency on libfmt 2022-12-01 15:50:34 +01:00
c7a0597fe7 util/Intrusive*: add C++20 concept checks 2022-12-01 15:43:51 +01:00
253d551684 lib/dbus/meson.build: add missing dependency on libfmt 2022-12-01 15:43:51 +01:00
00b7535cf1 util/Concepts: compatibility wrapper for std::predicate 2022-12-01 15:11:27 +01:00
5945877313 util/IntrusiveHashSet: add missing Cast()/ToHook() functions to IntrusiveHashSetMemberHookTraits 2022-12-01 15:10:42 +01:00
fe3e1d31bf util/IntrusiveHashSet: remove unused type alias "ListHookTraits" 2022-12-01 15:10:38 +01:00
65f1cafa43 util/IntrusiveHashSet: add method find_if() 2022-12-01 15:10:32 +01:00
d9b1f2fefa net/SocketAddress: add method HasPort() 2022-12-01 15:10:25 +01:00
e3ef0929f1 util/IntrusiveHashSet: add const overloads 2022-12-01 15:10:20 +01:00
8860962e09 util/IntrusiveHashSet: make several methods const 2022-12-01 15:10:13 +01:00
f13b8f669d util/IntrusiveList: simplify ToHook() overload with const_cast 2022-12-01 15:10:09 +01:00
fa58db798b lib/fmt/RuntimeError: new library
Replacing FormatRuntimeError().
2022-11-29 14:10:34 +01:00
45b13fc2a6 util/OptionParser: move to cmdline/
This library will depend on libfmt, and libutil shouldn't depend on
any library.
2022-11-29 11:32:16 +01:00
cf3f3a7750 lib/pulse/Error: use std::system_error 2022-11-29 09:56:47 +01:00
e455b93fac lib/nfs/Connection: use class NfsClientError 2022-11-29 09:45:25 +01:00
cf762f2a9d lib/icu/Error: std::system_error with UErrorCode 2022-11-29 09:31:48 +01:00
8ad0d919b1 lib/icuConverter, ...: use FmtBuffer() and FmtErrno() 2022-11-29 09:09:11 +01:00
4b5c8d1f3e mixer/meson.build: split libmixer_api from libmixer_glue 2022-11-29 09:09:11 +01:00
eb6c649d47 lib/fmt/SystemError: add concept check to work around ambiguous overloads 2022-11-29 09:09:10 +01:00
f2b025ca6c lib/alsa/meson.build: add dependency on libpcm_basic
For PcmExport::CalcInputSampleRate().
2022-11-29 09:09:10 +01:00
4328a6f77d lib/fmt/ToBuffer: fix FMT_VERSION check 2022-11-29 09:09:10 +01:00
97a6851525 lib/curl/Error: std::system_error with CURLcode 2022-11-29 06:33:32 +01:00
846d7dc317 lib/curl/Error: rename header to HttpStatusError.hxx 2022-11-29 06:33:32 +01:00
f62d61f088 lib/fmt/ToBuffer: add missing template parameters 2022-11-29 06:33:32 +01:00
1f33ac3e98 lib/upnp/Error: wrap libupnp errors in std::system_error 2022-11-29 00:32:48 +01:00
ed08a4bd58 lib/fmt/ToBuffer: use iterator instead of pointer 2022-11-28 23:10:25 +01:00
40d0828ccd util/StringBuffer: add non-const iterator 2022-11-28 23:10:01 +01:00
66029c405f system/FmtError: move to lib/fmt/ 2022-11-28 23:09:27 +01:00
7d8c076e06 lib/fmt/ToBuffer: include fmt/format.h on libfmt 7 to fix linker error 2022-11-28 23:03:52 +01:00
05dcac55f9 lib/fmt: add meson.build 2022-11-28 22:18:46 +01:00
2aa42d2647 lib/fmt/ToBuffer: new library 2022-11-28 22:18:46 +01:00
dc8e0c9c5c archive/zzip: add missing include 2022-11-28 22:18:45 +01:00
96ae659fdf system/FmtError: new library
Replaces the Format*() functions in system/Error.hxx.
2022-11-28 21:56:12 +01:00
124e75c286 thread/Thread, fs: add missing WIN32 includes 2022-11-28 21:56:11 +01:00
25da798e7a system/Clock: compile only on Windows 2022-11-28 21:16:49 +01:00
88d5347d94 Log, client/Response, io/BufferedOutputStream: remove unnecessary libfmt include 2022-11-28 20:44:48 +01:00
7f3868727b Log, client/Response, io/BufferedOutputStream: drop support for libfmt < 7
Remove some compatibility code.
2022-11-28 20:17:16 +01:00
b09a776a26 .travis.yml: remove obsolete file
We've migrated to GitHub actions in commit
c13911b171 a year ago
2022-11-28 20:17:16 +01:00
3103e8d719 fs/StandardDirectory: update #ifdef for GetEnvPath()
Fixes regression from a38eabc8bc
2022-11-28 20:17:16 +01:00
cfbd751742 fs/StandardDirectory: pass Path to IsValidDir() 2022-11-28 18:48:10 +01:00
a38eabc8bc fs/StandardDirectory: move code to GetExistingEnvDirectory() 2022-11-28 18:43:45 +01:00
9669ea6a12 fs/StandardDirectory: add noexcept 2022-11-28 18:27:06 +01:00
863a28daa3 fs/StandardDirectory: eliminate global variable "home_prefix" 2022-11-28 18:27:06 +01:00
ea5bcfed8b fs/StandardDirectory: pass std::string_view to ParseConfigLine() 2022-11-28 17:11:17 +01:00
f6f3c4c25b fs/StandardDirectory: pass const string to ParseConfigLine() 2022-11-28 17:07:29 +01:00
8fe29f5728 Merge tag 'v0.23.11'
release v0.23.11
2022-11-28 17:00:38 +01:00
1adc2c0c51 playlist_load_into_queue: log on failure to load song.
Log at level error when failing to load a song. Limit the number
of log messages produced to avoid flooding the log file when attempting
to load a large, broken playlist.

Closes 
2022-11-26 08:28:10 -08:00
a3b32819b1 event/Loop: split InjectBreak() from Break() 2022-11-22 22:30:12 +01:00
a57cf443ed event/Loop: set "again" in AddDefer() only if HAVE_THREADED_EVENT_LOOP
Only AddDefer()/AddIdle() calls from within DeferEvents are relevant.
2022-11-22 21:40:52 +01:00
d0d095cbcd util/IntrusiveHashSet: rename "slot" to "bucket" 2022-11-22 21:40:52 +01:00
3239fce5c1 util/IntrusiveHashSet: add remove_and_dispose_if() 2022-11-22 21:40:11 +01:00
200b770104 util/IntrusiveHashSet: add for_each() 2022-11-22 21:40:04 +01:00
3aa959eda7 util/IntrusiveHashSet: add erase_and_dispose() 2022-11-22 21:39:40 +01:00
72c047f4f0 util/IntrusiveHashSet: add hash_function(), key_eq() 2022-11-21 09:10:44 +01:00
c71958af4b input/async: pass std::span to AppendToBuffer() 2022-11-17 06:15:58 +01:00
ce13d82657 input/async: use std::byte instead of uint8_t 2022-11-17 06:15:19 +01:00
73dc8ff6bd lib/nfs/FileReader: pass std::span to OnNfsFileRead() 2022-11-17 06:15:16 +01:00
3278ad2ed8 storage/State: remove obsolete Boost compiler warning workaround 2022-11-17 05:32:29 +01:00
2e453ef58a storage/State: use std::hash() instead of boost::crc
Also eliminate the useless std::set.
2022-11-17 05:28:53 +01:00
a5d04be21f storage/State: add noexcept 2022-11-17 05:19:11 +01:00
9467df526c song/StringFilter: add enum Position
Replaces two conflicting bools.
2022-11-15 21:55:55 +01:00
9ca75589c0 song/StringFilter: simplify GetOperator() 2022-11-15 21:55:55 +01:00
c158abe87c lib/icu/Compare: use StringIsEqualIgnoreCase() 2022-11-15 21:13:01 +01:00
53530bd1d5 lib/icu/Canonicalize: convert all punctuation to ASCII
To make tag matching easier.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1669
2022-11-15 21:04:16 +01:00
d7f545721b lib/icu/Canonicalize: use unorm2_normalize() instead of u_strFoldCase()
unorm2_normalize() can case-fold as well, plus it applies Unicode
normalization which MPD should do for proper string comparisons.
2022-11-15 20:53:29 +01:00
8b72cb64b2 lib/icu/CaseFold: rename to IcuCanonicalize() and add flag parameter
Prepare for adding more transformations.
2022-11-15 20:53:04 +01:00
852df2239e lib/icu/Transliterator: pass std::basic_string_view<UChar> to constructor 2022-11-15 20:53:03 +01:00
5a1fbe60af test/TestStringFilter: new unit test 2022-11-15 20:52:53 +01:00
88e33b7b32 test/TestTagSongFilter: initialize ICU 2022-11-15 20:51:59 +01:00
264b3f8543 lib/icu/Collate: clear the global variable in IcuCollateFinish()
To allow repeated init/finish cycles.
2022-11-15 20:48:50 +01:00
ac2bce8b7b lib/icu/Transliterator: add missing include 2022-11-15 17:07:54 +01:00
9f3faaf3c4 lib/icu/Transliterator: wrapper for UTransliterator 2022-11-15 01:09:27 +01:00
7be39e07e1 lib/icu/Normalize: wrapper for unorm2_normalize() 2022-11-15 00:49:25 +01:00
154fb4317f lib/icu/CaseFold: move low-level wrapper to FoldCase.cxx 2022-11-15 00:46:58 +01:00
aad5210820 lib/icu/CaseFold: use ToStringView() 2022-11-15 00:36:47 +01:00
7c4fca0ae1 util/SpanCast: add ToStringView() template 2022-11-15 00:36:28 +01:00
1a6ec716ef lib/icu/Converter: add noexcept 2022-11-15 00:28:41 +01:00
0b22cc962d Merge branch 'private_users' of https://github.com/bluca/MPD 2022-11-14 23:53:43 +01:00
51769c40d8 util/IntrusiveSortedList: new class 2022-11-13 09:08:36 +01:00
85ab89a08b util/IntrusiveHashSet: add missing typename (to make clang happy) 2022-11-13 08:40:53 +01:00
a43062c575 RemoteTagCache: use IntrusiveHashSet instead of boost::intrusive::unordered_set 2022-11-13 08:39:04 +01:00
c943e27d51 util/IntrusiveHashSet: new class
Incomplete draft implementation, just enough methods for current
needs.
2022-11-13 08:38:53 +01:00
fb5d77158a util/IntrusiveList: add enum LinkMode
Compile-time code simplification.
2022-11-13 08:15:47 +01:00
3023816491 subprojects/.gitignore: ignore liburing 2022-11-12 12:40:44 +01:00
51e17e89f4 subprojects: add liburing.wrap 2022-11-12 12:30:13 +01:00
98c24d1a32 Merge branch 'v0.23.x' 2022-11-12 12:29:21 +01:00
f1dc1af85d util/IntrusiveList: use const_cast to eliminate duplicate HookTraits functions
I hate const_cast, but what I hate more is duplicate code.  Sigh.
2022-11-12 08:45:24 +01:00
7b3d870516 util/IntrusiveForwardList: remove unnecessary initializer from hook 2022-11-11 21:14:52 +01:00
963ff846ff test/util/TestIntrusiveForwardList: new unit test 2022-11-11 21:13:41 +01:00
48c4081ba1 test/util/TestIntrusiveList: remove unused code 2022-11-11 21:11:22 +01:00
970ccf043b util/SortList: enable the std::predicate kludge for macOS as well
Sigh.
2022-11-11 19:30:58 +01:00
0c92c12adf Merge branch 'v0.23.x' 2022-11-11 19:27:22 +01:00
29143dec87 util/SortList: kludge for Android NDK compatibility 2022-11-11 19:17:13 +01:00
0fd4c14043 db/simple/Directory: re-add Song.hxx to fix clang build failure 2022-11-11 19:13:01 +01:00
81e1f87e8c db/simple/{Directory,Song}: use IntrusiveList instead of boost::intrusive::list 2022-11-11 19:08:22 +01:00
a448d04d46 util/SortList: library which sorts linked lists 2022-11-11 19:03:39 +01:00
60e640af5a util/IntrusiveList: add single-item splice() overload 2022-11-11 18:29:50 +01:00
df15c418c7 util/IntrusiveList: fix swap() implementation if second list is empty 2022-11-11 18:29:50 +01:00
04ab8ae27b util/IntrusiveList: add type aliases value_type, pointer, reference 2022-11-11 17:15:20 +01:00
b4a64af15e util/IntrusiveList: constant_time_size is a template argument, not a variable 2022-11-11 17:15:16 +01:00
1ccfd1fb67 test/util/TestIntrusiveList: simplify tests 2022-11-11 16:41:24 +01:00
838c057231 util/IntrusiveList: use auto
Fixes typos in the const_iterator return types, and fixes returning
references to stack values.
2022-11-11 16:33:49 +01:00
af544bb16f util/IntrusiveList: fix typos 2022-11-11 10:11:42 +01:00
84fd401d21 util/IntrusiveList: add method splice() 2022-11-11 10:05:20 +01:00
b78d6c9dd7 test/util/TestIntrusiveList: add tests for reverse iterators 2022-11-11 09:53:00 +01:00
b5d224496f util/IntrusiveList: iterators are bidirectional 2022-11-11 09:20:09 +01:00
78d8b5f73c util/OptionalCounter: add operator+= and operator-= 2022-11-10 16:55:04 +01:00
5670d98c54 util/IntrusiveList: move code to IntrusiveListNode::Connect() 2022-11-10 16:52:34 +01:00
gd
440c676be2 EventLoop: added assert(IsInside()) in Insert(CoarseTimerEvent &) and AddIdle(DeferEvent &)
Like AddDefer(DeferEvent &), Insert(FineTimerEvent &), these methods don't lock to update EventLoop::again
2022-11-10 15:35:14 +01:00
e820222c5b lib/nfs/Manager: use IntrusiveForwardList instead of boost::intrusive::slist 2022-11-10 12:08:23 +01:00
1786eef8e6 util/IntrusiveForwardList: new class 2022-11-10 12:07:59 +01:00
5f2fa1dbe3 RemoteTagCache: use IntrusiveList instead of boost::intrusive::list 2022-11-10 12:06:00 +01:00
77d257de27 input/cache: use IntrusiveList instead of boost::intrusive::list 2022-11-10 12:05:09 +01:00
89d950e9a7 output/httpd: use IntrusiveList instead of boost::intrusive::list 2022-11-10 12:02:54 +01:00
4041d87c34 lib/nfs/Cancellable: use IntrusiveList instead of boost::intrusive::list 2022-11-10 12:01:11 +01:00
b3c5e6a3cc event/Loop: use IntrusiveList instead of boost::intrusive::list 2022-11-10 11:57:57 +01:00
1da8faa285 client/List: use IntrusiveList instead of boost::intrusive::list 2022-11-10 11:08:11 +01:00
988f5d1b5d util/StringSplit: add SplitWhile() 2022-11-09 19:23:19 +01:00
3ab3d5555e util/StringSplit: reimplement without std::distance()
Avoid including <iterator>.
2022-11-09 19:23:10 +01:00
2e5d46c399 util/StringSplit: add constexpr 2022-11-09 19:23:05 +01:00
7600ad7cac util/StringSplit: add Partition() 2022-11-09 19:22:54 +01:00
485ad583a0 util/CharUtil: add IsLowerAlphaNumericASCII() 2022-11-09 19:21:43 +01:00
bbc82a9892 io/FileDescriptor, net/SocketDescriptor: make lots of methods "const"
Only the file descriptor value itself is const, but the file itself
may be readable/writable.
2022-11-09 19:19:20 +01:00
69596106d3 io/FileDescriptor: add pread() wrapper 2022-11-09 19:18:41 +01:00
gd
6913148d99 Docs: changed sphinx theme from classic to sphinx_rtd_theme
Dependency: pip install sphinx-rtd-theme
2022-11-09 09:35:59 +02:00
gd
14460c6b6d Docs: added custom.css to override default hyphenation and text align styles 2022-11-08 17:31:37 +02:00
a0a11be79b Merge branch 'v0.23.x' 2022-11-08 14:36:09 +01:00
gd
4fa5bd9d5c doc/plugins.rst: changed 'More information' links to unnamed to suppress warning: Duplicate explicit target name 2022-11-08 14:34:45 +01:00
714bb991aa systemd: use PrivateUsers= in user unit
ProtectSystem= and other sandboxing options require a user namespace in
order to work as user units (the user manager does not run as root and
thus without a user namespace it is unable to perform mounts).
2022-11-03 23:11:13 +00:00
gd
a1359f2388 TagBuilder: skip unnecessary preperation if there are no items to add 2022-11-01 17:55:42 +02:00
gd
ab687481cc Tag: skip tag pool lock if there are no items 2022-11-01 15:37:54 +02:00
0efbd4df8b lib/gcrypt: use std::size_t 2022-10-29 07:31:25 +02:00
gd
caaa050e60 curl input plugin - added config options: verbose, low_speed_limit, low_speed_time, tcp_keepalive, tcp_keepidle, tcp_keepintvl 2022-10-22 13:49:58 +03:00
b4e3891912 Merge branch 'config_curl_conn_timeout' of https://github.com/geneticdrift/MPD 2022-10-16 11:45:19 +02:00
gd
160f793e2a Added connect_timeout configuration to curl input plugin 2022-10-16 12:13:51 +03:00
1429d6bfb9 playlist/cue/Parser: use Split() 2022-10-15 08:33:51 +02:00
ced6a5ae07 playlist/cue/Parser: remove always-failing assert()
Not the assert() here fails, but the illegal src[-1] call.  Yet
another regression from commit 21e4c25e61
2022-10-15 08:32:37 +02:00
d6d0f78e93 Merge tag 'v0.23.10'
release v0.23.10
2022-10-14 23:56:33 +02:00
2937a55582 add precondition for mount/unmount in commands response 2022-10-07 13:59:54 +02:00
209e4e940e Merge branch 'queue_save_with_append' of https://github.com/geneticdrift/MPD 2022-10-02 11:41:17 +02:00
gd
cd093a6014 Added new optional argument MODE to command 'save' to be able to append or replace an existing playlist 2022-10-02 11:19:36 +03:00
b0d6c0e7cb Merge branch 'v0.23.x' 2022-09-28 13:08:34 +02:00
ac7bf12743 event/Loop: move call to FlushClockCaches() 2022-09-28 10:03:39 +02:00
db21e20c99 event/Loop: improve API doc wording 2022-09-28 09:55:35 +02:00
56adb27b44 event/Loop: push new idle events to the back of the list 2022-09-28 09:47:36 +02:00
520e96b6e8 event/Loop: rename parameter 2022-09-28 09:45:58 +02:00
45599e7840 Merge branch 'v0.23.x' 2022-09-27 20:40:41 +02:00
8d9b0c42cb Merge branch 'reflection' of https://github.com/jcorporation/MPD 2022-09-27 20:35:17 +02:00
2c11095eed lib/icu/Compare: use StringStartsWith() for improved code clarity
Also fixes the inverted strncmp() call.
2022-09-27 20:23:10 +02:00
07a0369b74 Add pcre status to config response 2022-09-27 20:10:35 +02:00
cd253e470a Merge branch 'starts_with' of https://github.com/jcorporation/MPD 2022-09-27 20:05:38 +02:00
868a06eaf9 Add starts_with to filter expressions 2022-09-27 19:45:15 +02:00
512cd7b0de Merge branch 'ConsumeMode' of https://github.com/jcorporation/MPD 2022-09-21 11:36:25 +02:00
352c598916 command/other: use if-with-initializer 2022-09-20 22:07:10 +02:00
661aee29da Merge branch 'reflection' of https://github.com/jcorporation/MPD 2022-09-20 21:07:06 +02:00
0439df05cc Add playlist_directory to config command response 2022-09-20 21:04:25 +02:00
4333854293 Add documentation for consume oneshot mode 2022-09-20 20:32:32 +02:00
eb3baf7e99 Cast enum to unsigned 2022-09-20 20:27:25 +02:00
48a936ef5b Add ConsumeMode oneshot, closes 2022-09-20 20:26:49 +02:00
5a7d2be77d Merge remote-tracking branch 'jcorporation/idle' 2022-09-20 15:11:41 +02:00
310a146a55 OutputCommands get ride of global mixer idle events 2022-09-06 21:58:18 +02:00
0e201ffdcc archive/iso9660: simplify std::span initializer 2022-09-06 21:16:28 +02:00
d5d25d78da Merge branch 'v0.23.x' 2022-09-06 21:15:42 +02:00
4f8b4c605e player/Control: Change idle events from global to partition scope 2022-08-28 11:33:14 +02:00
b2fb920d28 android/PrivacyPolicy.rst: add Privacy Policy
The Google overlords require me to publish a privacy policy, even if
MPD does not collect any data.
2022-08-18 18:53:10 +02:00
4f041694d3 Merge tag 'v0.23.9'
release v0.23.9
2022-08-18 18:23:12 +02:00
51aa1d2db8 mixer/Internal: hide internal fields 2022-08-18 17:42:30 +02:00
2d2df25d04 mixer/Mixer: avoid locking twice 2022-08-18 17:39:17 +02:00
29eb3e9ebc mixer/Control: move some code to Lock*() methods 2022-08-18 17:34:00 +02:00
b0873fbc90 mixer/Mixer*: drop the "Mixer" prefix from source files 2022-08-18 17:21:39 +02:00
c14484a5cc mixer/MixerList: eliminate header 2022-08-18 17:14:42 +02:00
a966cfeb1f playlist/cue/CueParser: fix nullptr dereference
Regression from commit 21e4c25e61
2022-08-18 17:06:51 +02:00
6c0546d829 mixer/Internal: document that caller must lock the mutex 2022-08-18 16:57:58 +02:00
e1e8f45983 mixer/Control: add noexcept 2022-08-18 16:56:32 +02:00
3eedcc55b9 mixer/Control: convert pointers to references 2022-08-18 16:56:06 +02:00
dd2cab1488 Merge branch 'v0.23.x' 2022-08-18 16:54:18 +02:00
f883c09b6b fs/FileSystem: add pure attributes 2022-08-18 16:53:32 +02:00
71acad6c21 fs/FileSystem: add noexcept 2022-08-18 16:53:31 +02:00
938054bdb8 command/all: fix off-by-one bug in parameter count check 2022-08-09 12:47:57 +02:00
d0909adf6b command/all: use class StaticVector 2022-08-09 12:46:26 +02:00
a12b004fa4 util/StaticVector: new class 2022-08-09 12:44:02 +02:00
a8452957fc command/Request: pass std::span to constructor 2022-08-09 12:43:52 +02:00
feb334756e command/all: convert macro to constexpr 2022-08-09 12:39:18 +02:00
50a4d7169e TagAny: pass std::string_view to uri_has_scheme() 2022-08-09 11:43:35 +02:00
6239b6c0e2 Merge branch 'v0.23.x' 2022-08-08 23:48:38 +02:00
b789ffd2bf Merge branch 'v0.23.x' 2022-08-08 23:46:22 +02:00
0279f4fb57 output/jack: fix bogus assertion failure
Regression from commit 45071607aa

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1571
2022-08-08 22:01:59 +02:00
88793cbc1a output/httpd: avoid extra buffer copy if possible 2022-08-08 21:00:38 +02:00
2afe427ab3 output/httpd: copy from returned encoder buffer
This fixes a regression from commits c266fb7758 and 00b8ced09f,
but really caused by API change in commit 7e14f8f830, and this
plugin's failure to adapt to this API change.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1585
2022-08-08 21:00:27 +02:00
4c08c0b8b1 Merge branch 'v0.23.x' 2022-07-27 11:06:47 +02:00
b864094fdc Merge branch 'master' of https://github.com/Sonico98/MPD 2022-07-21 21:14:15 +02:00
3ef83cc34e Add titleSort tag 2022-07-20 23:05:10 -03:00
3f133dd586 use data() instead of &[0]
No need for C pointer manipulation.

Removed data() for string_view as [] can be used without.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2022-07-20 13:50:48 -07:00
0c98d93e9a io/FileOutputStream: write to temporary file if O_TMPFILE is not available 2022-07-14 18:45:33 +02:00
c344403bed fs/Path: add operator+ 2022-07-14 18:42:25 +02:00
150e8f78bf io/FileOutputStream: use fsync() if fdatasync() is unavailable
Fixes the macOS build which apparently doesn't implement the POSIX
function fdatasync().
2022-07-14 18:34:44 +02:00
bc7fdba36d test/fs/TestPath: add missing PATH_LITERAL 2022-07-14 18:34:43 +02:00
fe3ab7b937 fs/Path: add WithSuffix() 2022-07-14 18:23:48 +02:00
458084d79b fs/Path: add GetSuffix() 2022-07-14 18:20:55 +02:00
f44bc19ce1 test/fs/TestPath: new unit test 2022-07-14 18:20:45 +02:00
d3947d0ad5 fs/Path: GetExtension() skips all leading dots
Don't return an empty string for "..", because this path doesn't have
an extension.
2022-07-14 18:20:45 +02:00
849ed122c7 fs/Path: document GetExtension() 2022-07-14 18:12:00 +02:00
254ee00c37 fs/Path: rename GetSuffix() to GetExtension()
The "extension" is the name after the dot, but the "suffix" is the
string including the dot.
2022-07-14 18:12:00 +02:00
594b97feb1 fs/Path: change cast syntax 2022-07-14 18:12:00 +02:00
cc0def15c4 Copyright year 2022 2022-07-14 17:59:35 +02:00
81154130b5 test/fs: rename TestFs.cxx to TestGlob.cxx 2022-07-14 17:57:10 +02:00
0514f25c61 test/TestFs: move to test/fs/ 2022-07-14 17:56:37 +02:00
2670bbdcc8 io/FileOutputStream: simplify OpenTempFile() call 2022-07-14 15:47:10 +02:00
bd3e096411 io/FileOutputStream: move code to Delete() 2022-07-14 15:43:36 +02:00
270a74e53b io/FileOutputStream: add method Sync() 2022-07-14 15:41:12 +02:00
47d103e8a1 io/FileOutputStream: add API documentation 2022-07-14 15:41:03 +02:00
188f7ab795 thread/WindowsCond: add explicit cast 2022-07-14 13:04:08 +02:00
4953a57c1c java/String: add std::string_view constructor 2022-07-14 13:03:23 +02:00
199037c682 config: allow configuring partitions
This just allows creating empty partitions.  More features to come.
2022-07-13 15:18:06 +02:00
64f84d5468 player/Listener: add virtual method OnPlayerState(), wrapping IDLE_PLAYER
This eliminates most of the remaining global "player" idle events.
2022-07-13 14:11:36 +02:00
047561dc22 player/Listener: add virtual method OnPlayerError()
Replaces two global idle_add() calls.
2022-07-13 14:11:36 +02:00
a542a0804a Partition: OnPlayerTagModified() emits IDLE_PLAYER
Replaces one global idle_add() call.
2022-07-13 14:11:36 +02:00
cddeb2a0df io/BufferedOutputStream: add missing #include 2022-07-13 14:11:36 +02:00
de1d443db1 output/Multiple: use std::size_t 2022-07-13 13:26:27 +02:00
e2040ed395 output/Multiple: use [[gnu::pure]] 2022-07-13 13:25:17 +02:00
8a0ba7a725 output/Control: GetName() returns std::string& 2022-07-13 13:23:21 +02:00
e74788ea32 output/Control: inline GetName() 2022-07-13 13:13:23 +02:00
fef79931c5 output/Multiple: pass std::string_view to FindByName() 2022-07-13 13:13:21 +02:00
b52b0ac85a *: use BufferedOutputStream::Fmt() 2022-07-13 13:10:14 +02:00
9a30286289 io/BufferedOutputStream: add libfmt support 2022-07-13 12:52:20 +02:00
20310437d0 .github/workflows/build.yml: build with Ubuntu 22.04 as well 2022-07-13 12:41:04 +02:00
d29e1544bf .github/workflows/build.yml: explicitly select ubuntu-20.04
According to https://github.com/actions/virtual-environments
"ubuntu-latest" maps to "ubuntu-20.04", even though "ubuntu-22.04" is
also available.  Since our job description is very specific to
"ubuntu-20.04", let's select this explicitly.
2022-07-13 12:37:02 +02:00
ae4f4d3533 config/Data: add WithEach(ConfigBlockOption)
To improve error messages without making callers more complex.
2022-07-13 11:05:21 +02:00
89a18b49a7 Merge branch 'v0.23.x' 2022-07-12 14:00:00 +02:00
eb589b0a46 output/osx: fix CI failure 2022-07-12 13:37:46 +02:00
52eff41379 remove Haiku support
Haiku support has been unmaintained for many years, and this issue has
been open for more than 5 years, but apparently the Haiku people have
lost interest:

 https://github.com/MusicPlayerDaemon/MPD/pull/183

Haiku support was therefore deprecated by this commit 4 years ago:
7de8fd04a4 - but in those 4 years, nobody stepped up to adopt
maintainership.

I don't have any computer (or VM) with Haiku and there is no CI with
Haiku support, so I'm unable to adapt the Haiku specific code to API
changes.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/182
Closes https://github.com/MusicPlayerDaemon/MPD/issues/185
2022-07-12 13:14:49 +02:00
45071607aa output/Interface: pass std::span to Play() 2022-07-12 12:59:47 +02:00
f5d104e7af output/ao: simplify write_size checks 2022-07-12 12:58:19 +02:00
4f8d2a8b1c output/alsa: use std::byte instead of uint8_t 2022-07-12 12:36:39 +02:00
0158a2b6b9 encoder/flac: refactor input buffer conversion 2022-07-12 12:31:08 +02:00
00b8ced09f encoder/flac: Read() returns the internal buffer 2022-07-12 12:19:55 +02:00
5f51be43cf decoder/flac: add noexcept and inline 2022-07-12 12:15:06 +02:00
3e2de560ca encoder/lame: eliminate the audio_format field 2022-07-12 12:08:46 +02:00
c266fb7758 encoder/lame: Read() returns the internal buffer
Eliminate memcpy() calls.
2022-07-12 12:01:31 +02:00
0d09f307b2 encoder/Interface: update API docs 2022-07-12 12:00:02 +02:00
eb7d321cb8 Merge branch 'v0.23.x' 2022-07-12 11:59:49 +02:00
7e14f8f830 encoder/Interface: pass std::span to Write() and Read() 2022-07-12 10:33:59 +02:00
28e044a36a encoder/lame: use std::size_t 2022-07-12 10:14:10 +02:00
4e91d8279b encoder/vorbis: use std::size_t 2022-07-12 10:11:30 +02:00
ff3d8509ac output/httpd: move buffer to stack 2022-07-12 10:08:26 +02:00
e861d4f83d encoder/interface: make Read() noexcept (all implementations are) 2022-07-12 10:07:38 +02:00
31d89b36cf encoder/flac: use std::size_t 2022-07-12 09:53:16 +02:00
6b24344031 output/shout: move buffer to stack 2022-07-12 09:48:02 +02:00
c55e250c45 encoder/Interface: include cleanup 2022-07-11 22:38:24 +02:00
cd241a93c1 util/DynamicFifoBuffer: pass std::span to Append() 2022-07-11 22:38:24 +02:00
53acf7ae82 encoder/*: use std::byte instead of uint8_t 2022-07-11 22:38:24 +02:00
c34f6ed8c0 decoder/Client: pass std::span to SubmitData() 2022-07-11 22:37:38 +02:00
329c448d30 decoder/wavpack: use [[gnu::pure]] 2022-07-11 22:11:42 +02:00
a6619e9a13 decoder/wavpack: add "constexpr" and "const_cast" 2022-07-11 22:10:11 +02:00
24ce5da2b8 decoder/wavpack: convert pointer to reference 2022-07-11 22:08:49 +02:00
b4f751080d decoder/wavpack: add noexcept 2022-07-11 22:06:10 +02:00
6d02edebc9 decoder/wavpack: rename "samples" to "frames" 2022-07-11 22:05:49 +02:00
349882ed75 decoder/wavpack: require libwavpack version 5 2022-07-11 22:04:15 +02:00
4464310e74 Merge tag 'v0.23.8'
release v0.23.8
2022-07-09 01:08:16 +02:00
4b3dcf831b output/Timer: add noexcept 2022-07-08 22:58:45 +02:00
7dd65f3028 Merge branch 'v0.23.x' 2022-07-04 19:21:18 +02:00
bc56f8c2f0 util/ConstBuffer: remove obsolete library
Everything has been migrated to std::span.
2022-07-04 19:15:10 +02:00
596ff7e6bf output/*: use std::span instead of ConstBuffer 2022-07-04 19:14:12 +02:00
e8667f99be util/OptionParser: use std::span instead of ConstBuffer 2022-07-04 19:04:16 +02:00
9b427b3171 command/*: use std::span instead of ConstBuffer 2022-07-04 18:58:13 +02:00
baff5e5594 lib/yajl: use std::span instead of ConstBuffer 2022-07-04 18:37:36 +02:00
020c9b41cc lib/icu: use std::span instead of ConstBuffer 2022-07-04 18:37:35 +02:00
e975e2e477 lib/ffmpeg: use std::span instead of ConstBuffer 2022-07-04 18:37:35 +02:00
4e1dc562f7 lib/curl: use std::span instead of ConstBuffer 2022-07-04 18:37:35 +02:00
d097babe73 lib/chromaprint: use std::span instead of ConstBuffer 2022-07-04 18:37:35 +02:00
8fa212f04d lib/cdio: use std::span instead of ConstBuffer 2022-07-04 18:37:35 +02:00
b9c9a5f1dd db/*: use std::span instead of ConstBuffer 2022-07-04 18:37:35 +02:00
4fb8b45111 song/Filter: use std::span instead of ConstBuffer 2022-07-04 18:37:35 +02:00
6c107443d3 input/qobuz: include cleanup 2022-07-04 18:37:35 +02:00
67c6d111a8 filter/*: use std::span instead of ConstBuffer 2022-07-04 18:37:35 +02:00
18ebd42c52 .github: Add reminder to include backtrace in issue template 2022-07-04 10:32:58 -06:00
9675cc77e2 decoder/*: use std::span instead of ConstBuffer 2022-07-04 18:11:21 +02:00
4ce1dae673 pcm/*: use std::span instead of ConstBuffer 2022-07-04 18:11:21 +02:00
d89136b09c util/ConstBuffer: hard-code std::span support 2022-07-04 18:09:32 +02:00
d58c38943a util/StringView: remove obsolete class
Everything has been migrated to std::string_view.
2022-07-04 15:04:31 +02:00
66704ec879 util/UriExtract: use std::string_view instead of StringView 2022-07-04 15:04:31 +02:00
422c1e9288 util/TemplateString: remove StringView support 2022-07-04 15:04:31 +02:00
683f0da2e7 tag/*: use std::string_view instead of StringView 2022-07-04 15:04:31 +02:00
c7a8fc91c0 storage/curl: use std::string_view instead of StringView 2022-07-04 15:04:31 +02:00
cfd255a014 lib/xiph: use std::string_view instead of StringView 2022-07-04 15:04:31 +02:00
1c30b3d5a1 lib/dbus/UDisks2: use std::string_view instead of StringView 2022-07-04 15:04:31 +02:00
4964eda167 fs/StandardDirectory: use std::string_view instead of StringView 2022-07-04 15:04:31 +02:00
502e5f006a decoder/*: use std::string_view instead of StringView 2022-07-04 14:50:18 +02:00
23235e3194 db/upnp/Directory: use std::string_view instead of StringView 2022-07-04 14:50:18 +02:00
93834fe389 db/simple/Directory: use std::string_view instead of StringView 2022-07-04 14:50:18 +02:00
bd32b229b5 config/Path: use std::string_view instead of StringView 2022-07-04 14:41:39 +02:00
c7d2cb855a Permission: use std::string_view instead of StringView 2022-07-04 14:38:29 +02:00
04c924ae3b playlist/Registry: use std::string_view instead of StringView 2022-07-04 14:36:21 +02:00
6c8a85a391 playlist/{asx,cue,rss,xspf}: use std::string_view instead of StringView 2022-07-04 14:35:52 +02:00
74780131bd lib/zlib/GzipOutputStream: add SyncFlush() 2022-07-04 10:09:04 +02:00
2c092d2613 lib/zlib/GzipOutputStream: add exception API docs 2022-07-04 10:08:55 +02:00
171b31ae67 lib/zlib/GzipOutputStream: rename Flush() to Finish() 2022-07-04 10:08:54 +02:00
5b3abe2c9c lib/zlib/GzipOutputStream: grow Write() buffer to 64 kB 2022-07-04 10:08:53 +02:00
59186f1fb0 event/Loop: include cleanup 2022-07-04 09:55:48 +02:00
5e68531428 event/SocketEvent: move ssize_t to class BufferedSocket 2022-07-04 09:54:08 +02:00
e7b15a9041 lib/curl/Request: remove obsolete method prototypes 2022-07-02 18:42:08 +02:00
853afa1bce lib/curl/Adapter: add missing StripLeft() call
Fixes regression by commit 88a66df9d6
2022-07-02 18:36:15 +02:00
627fd755e8 lib/curl/Adapter: remove redundant size check 2022-07-01 16:54:47 +02:00
88a66df9d6 lib/curl/Adapter: use std::string_view internally 2022-07-01 16:51:37 +02:00
af951dc08a Merge branch 'v0.23.x' 2022-07-01 12:45:07 +02:00
a6d20d1907 Merge branch 'v0.23.x' 2022-07-01 12:39:41 +02:00
d882c3361d playlist/PlaylistPlugin: use std::string_view 2022-07-01 11:31:31 +02:00
9d50306e2f lib/xiph/ScanVorbisComment: use std::string_view 2022-07-01 11:30:44 +02:00
96f99aeb8f TagPrint: use std::string_view 2022-07-01 11:29:58 +02:00
ed7263ee3e decoder/OpusTags: use std::string_view 2022-07-01 11:29:11 +02:00
f32d752ccb util/NumberParser: use std::string_view 2022-07-01 11:29:11 +02:00
671b7e079f decoder/OpusReader: use std::string_view 2022-07-01 11:29:11 +02:00
e10b15010c decoder/OpusReader: add noexcept 2022-07-01 11:29:11 +02:00
02fe857755 util/IterableSplitString: return std::string_view 2022-07-01 11:29:11 +02:00
ea3f044cd8 util/SplitString: use std::string_view 2022-07-01 11:29:11 +02:00
e6bb6c59ec storage/Composite: use std::string_view 2022-07-01 11:29:11 +02:00
6d23ac67f9 util/UriQueryParser: use std::string_view 2022-07-01 11:29:10 +02:00
ca46b4d7a7 util/MimeType: use std::string_view 2022-07-01 11:29:10 +02:00
0727ee94c0 tag/Id3Scan: use std::string_view 2022-07-01 11:29:10 +02:00
21e4c25e61 playlist/cue/CueParser: more std::string_view 2022-07-01 11:29:10 +02:00
e921c0b40b lib/yajl/Callbacks: use std::string_view 2022-07-01 11:16:42 +02:00
c05d4cddfb input/qobuz: use std::string_view 2022-07-01 11:16:42 +02:00
c9723ee4b7 playlist/SoundCloud: use std::string_view 2022-07-01 11:16:42 +02:00
ca90c75c61 lib/alsa/AllowedFormat: pass std::string_view to constructor 2022-07-01 10:57:49 +02:00
9976665cc7 util/UriRelative: use std::string_view internally 2022-07-01 10:56:29 +02:00
c5f037fa64 util/StringCompare: move code from StringView 2022-07-01 10:48:34 +02:00
5ec13c0b06 util/StringStrip: add libc++ compatibility kludge 2022-07-01 10:45:37 +02:00
60ca12e4bd db/simple/Song: use std::string_view 2022-06-30 21:04:13 +02:00
67fcf7d7c5 output/ao: add missing include 2022-06-30 21:03:25 +02:00
c953ed48b7 output/ao: use std::string_view 2022-06-30 21:01:29 +02:00
6440df60aa output/jack: use std::string_view 2022-06-30 21:00:23 +02:00
b806b0a97f util/StringStrip: add std::string_view overloads 2022-06-30 21:00:07 +02:00
10197a0041 util/IterableSplitString: use std::string_view internally 2022-06-30 20:54:42 +02:00
166885802a util/StringSplit: move code from StringView.hxx 2022-06-30 20:40:41 +02:00
4a97c45585 tag/Config: use IterableSplitString instead of SplitString() 2022-06-30 20:39:39 +02:00
0173d3b313 util/IterableSplitString: use StringView::Split() 2022-06-30 20:37:58 +02:00
aadd32c973 util/IterableSplitString: add noexcept 2022-06-30 20:34:04 +02:00
0f4bf5569a event/InotifyEvent: new class wrapping inotify
Replaces class InotifySource.
2022-06-30 12:05:50 +02:00
ff4cf6c6d1 test/run_inotify: add class Instance 2022-06-30 11:57:03 +02:00
a7b7e35512 tag/ReplayGainParser: use std::string_view 2022-06-30 10:59:56 +02:00
11135b48e6 tag/MixRampParser: use std::string_view 2022-06-30 10:59:27 +02:00
d0382caa88 tag/ApeLoader: use std::string_view 2022-06-30 10:58:22 +02:00
4765726bda tag/VorbisComment: use std::string_view 2022-06-30 10:57:01 +02:00
455a412aaa tag/Table: use std::string_view 2022-06-30 10:53:26 +02:00
1a2b505979 tag/ParseName: use std::string_view 2022-06-30 10:52:21 +02:00
c34f3c9b94 tag/Handler: use StringIsEqualIgnoreCase() 2022-06-30 10:50:56 +02:00
232084c2f9 playlist/cue/CueParser: use std::string_view in public API 2022-06-30 10:50:53 +02:00
2ba092711f event/net/UdpListener: use IsSocketErrorReceiveWouldBlock() 2022-06-30 10:32:25 +02:00
8aa4227c0c net/SocketAddress: add std::span cast operators 2022-06-30 10:30:54 +02:00
81afb47cd0 util/ByteOrder: add class PackedBE64 2022-06-30 10:30:54 +02:00
60a3aae35f io/FileDescriptor: add OpenReadOnly() overload with directory fd 2022-06-30 10:30:54 +02:00
bc3415ce8b Copyright year 2022 2022-06-30 09:41:53 +02:00
3f1acd3642 lib/avahi/Publisher: fix comment typo 2022-06-30 09:38:44 +02:00
4564d251a8 zeroconf/avahi: move generic sources to lib/avahi 2022-06-30 09:37:30 +02:00
8783ed1981 lib/curl/Adapter: use std::string_view 2022-06-29 17:38:58 +02:00
1da09f5b1b lib/curl: use std::span 2022-06-29 17:37:12 +02:00
062df65b1e lib/dbus: use std::span 2022-06-29 17:32:58 +02:00
899eaa3307 io/FileDescriptor: add Duplicate() returning UniqueFileDescriptor 2022-06-29 17:31:37 +02:00
5140eaa5e7 util/IntrusiveList: use std::is_base_of_v 2022-06-29 17:30:11 +02:00
cca20fec07 event/FineTimerEvent: adjust "friend" declaration 2022-06-29 17:29:44 +02:00
12d67dad35 net/SocketError: support ETIMEDOUT 2022-06-29 17:28:47 +02:00
8a68d085b4 util/IntrusiveList: add option "constant_time_size" 2022-06-29 17:28:39 +02:00
e437cc4faf util/IntrusiveList: add size() 2022-06-29 17:28:35 +02:00
1fb858e2d7 util/IntrusiveList: add struct IntrusiveListMemberHookTraits 2022-06-29 17:28:16 +02:00
3945a3add9 util/MemberPointer: new library 2022-06-29 17:28:15 +02:00
5348a446a7 util/IntrusiveList: move various static functions to struct IntrusiveListBaseHook 2022-06-29 17:27:40 +02:00
e8e33d5fc4 util/IntrusiveList: add missing ToHook() calls 2022-06-29 17:27:37 +02:00
c28580745b util/IntrusiveList: move struct HookDetection to top-level 2022-06-29 17:24:08 +02:00
e7b587d550 util/CopyConst: use std::add_const 2022-06-29 17:23:50 +02:00
5d34b9b5bb util/SpanCast: move CopyConst to separate header 2022-06-29 17:23:44 +02:00
86be7938f1 util/SpanCast: swap the CopyConst template parameters 2022-06-29 17:23:41 +02:00
7ad5a5efec util/OffsetPointer: use std::byte 2022-06-29 17:23:32 +02:00
64f2735e60 util/SpanCast: add ToStringView() 2022-06-29 17:23:14 +02:00
3a0a0facdf util/SpanCast: suppress alignment warnings 2022-06-29 17:23:13 +02:00
ec66ee3bfb tag/Handler: use std::string_view instead of StringView 2022-06-29 17:22:17 +02:00
ca9dd74fbf tag/Builder: use std::string_view instead of StringView 2022-06-29 17:22:17 +02:00
2da847dd30 tag/Pool: use std::string_view instead of StringView 2022-06-29 17:22:17 +02:00
4cb5c3782b util/HexFormat: require std::span 2022-06-29 17:22:17 +02:00
dcf39ee44e .github/workflows/build.yml: add "python-version: 3.x"
This appears to be necessary as of actions/setup-python@v4 (commit
45d908e25f).
2022-06-13 21:37:04 +02:00
f2cfa3e1c4 net/SocketError: add SocketErrorCategory() 2022-06-13 21:26:58 +02:00
0c2c20254b system/Error: add IsLastError() 2022-06-13 21:23:11 +02:00
193d6a4fd4 system/Error: add LastErrorCategory() 2022-06-13 21:19:20 +02:00
acfeec7a5d system/Error: add [[gnu::const]] attribute 2022-06-13 21:16:24 +02:00
45d908e25f build(deps): bump actions/setup-python from 3 to 4
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-13 15:23:52 +00:00
b4f454a553 Merge pull request from MusicPlayerDaemon/dependabot/github_actions/actions/setup-python-3
build(deps): bump actions/setup-python from 1 to 3
2022-06-08 12:56:55 +02:00
299f813e28 Merge pull request from MusicPlayerDaemon/dependabot/github_actions/actions/checkout-3
build(deps): bump actions/checkout from 2 to 3
2022-06-08 12:56:21 +02:00
eedd490e2d net/AddressInfo: add iterator type aliases 2022-06-07 10:11:26 +02:00
0a8aca516a util/StringBuffer: use data() instead of &front() 2022-06-07 10:11:05 +02:00
70808bde64 util/ForeignFifoBuffer: add MoveFrom() overload with std::span 2022-06-07 10:09:08 +02:00
93bf0fc547 util/ForeignFifoBuffer: use iterators 2022-06-07 10:08:58 +02:00
95e7f8b1c8 util/ForeignFifoBuffer: more constexpr 2022-06-07 10:08:58 +02:00
e2d6bb7444 build(deps): bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-05 08:28:29 +00:00
f89916e6fb build(deps): bump actions/setup-python from 1 to 3
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 1 to 3.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v1...v3)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-05 08:28:27 +00:00
7d95b15cbc chore: Included githubactions in the dependabot config
This should help with keeping the GitHub actions updated on new releases. This will also help with keeping it secure.

Dependabot helps in keeping the supply chain secure https://docs.github.com/en/code-security/dependabot

GitHub actions up to date https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot

https://github.com/ossf/scorecard/blob/main/docs/checks.md#dependency-update-tool
Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>
2022-06-05 01:30:13 +00:00
27e78c71e0 util/HexFormat: use std::span instead of ConstBuffer 2022-06-01 22:50:54 +02:00
8333927737 time/Zone: add native Windows implementation 2022-06-01 22:35:04 +02:00
db03db0dca util/SpanCast: add FromBytesStrict() 2022-06-01 21:50:01 +02:00
bd96f6e572 util/SpanCast: add const support to FromBytesFloor() 2022-06-01 21:49:35 +02:00
04041f9583 util/Manual: use std::aligned_storage_t
By using std::launder(), we can re-enable -Wstrict-aliasing.
2022-05-31 16:44:07 +02:00
826d1b207e util/Manual: add type aliases 2022-05-31 16:44:07 +02:00
f92bae887f util/Manual: add noexcept 2022-05-31 16:44:07 +02:00
d2983b7fde net/SocketAddress: include cleanup 2022-05-31 13:54:19 +02:00
059955a48c net/SocketAddress: add #ifdefs for std::span 2022-05-31 13:51:12 +02:00
6ebac6a0b2 net/StaticSocketAddress: use std::string_view instead of StringView 2022-05-31 13:49:18 +02:00
b5a9d0654e net/Resolver: use std::copy() 2022-05-31 13:44:25 +02:00
242ba727b2 net/HostParser: use std::string_view instead of StringView 2022-05-31 13:44:25 +02:00
d5db4ca0e7 net/SocketAddress: GetSteadyPart() returns std::span 2022-05-31 13:32:27 +02:00
d256d3dabe util/StringCompare: use std::string_view instead of StringView 2022-05-31 13:24:45 +02:00
759da033fc lib/curl/Escape: use std::string_view instead of StringView 2022-05-31 13:22:56 +02:00
c074338f4c system/EventFD: include cleanup 2022-05-31 12:43:26 +02:00
3dd2434149 lib/crypto/Base64: add overload which returns AllocatedArray<std::byte> 2022-05-24 14:29:41 +02:00
3699514d18 lib/xiph/VorbisPicture: use std::string_view instead of StringView 2022-05-24 14:24:48 +02:00
f045cf43e4 output/snapcast/Client: work around clang 14 std::span cast bug
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1538
2022-05-24 14:18:50 +02:00
843dad19e9 output/snapcast/Client: use std::string_view instead of StringView 2022-05-24 14:18:33 +02:00
73e2ac4211 tag/FixString: use std::string_view instead of StringView 2022-05-24 14:18:33 +02:00
6d113de1f8 tag/Handler: pass std::span to OnPicture() 2022-05-24 14:18:33 +02:00
2e6f115bcc Merge branch 'v0.23.x' 2022-05-24 10:58:40 +02:00
97f78059a2 util/AllocatedArray: add missing type alias "value_type" 2022-05-23 22:15:20 +02:00
fd47edb905 apple/AudioObject: call AllocatedArray::data() instead of begin()
Since commit 5fb97b81d1, begin() returns
an iterator class and not a pointer.

Fixes one part of https://github.com/MusicPlayerDaemon/MPD/issues/1538
2022-05-23 22:06:54 +02:00
8ee442e9b1 Merge branch 'v0.23.x' 2022-05-23 21:35:26 +02:00
6633c7fd42 lib/crypto/Base64: use std::string_view 2022-05-20 11:25:04 +02:00
01b32d5ee0 util/WritableBuffer: remove unused library 2022-05-20 11:22:03 +02:00
1260a0147a lib/crypto/Base64: use std::span 2022-05-20 11:21:44 +02:00
ef54b7d9de archive/iso9660: use std::span 2022-05-20 11:15:45 +02:00
f66315d2de MusicChunk: use std::span 2022-05-20 11:15:45 +02:00
b50173ae8b util/CircularBuffer: use std::span 2022-05-20 11:15:45 +02:00
b37c031fd1 util/{HugeAllocator,SparseBuffer}: use std::span 2022-05-20 11:15:45 +02:00
84e5da4bf0 pcm/Silence: use std::span 2022-05-20 11:15:45 +02:00
3bb7693200 decoder/HybridDsd: remove
This is a proprietary extension which nobody appears to use.
2022-05-20 10:08:17 +02:00
b22c00d0cd Merge branch 'v0.23.x' 2022-05-20 10:04:19 +02:00
7006b075c3 util/AllocatedArray: fix -Wunused-parameter 2022-05-20 09:48:49 +02:00
774024a41b net/SocketAddress: add std::span cast operator 2022-05-19 20:52:48 +02:00
5fb97b81d1 util/AllocatedArray: migrate from {Const,Writable}Buffer to std::span 2022-05-19 20:52:48 +02:00
23dd613ff9 system/VmaName: suppress -Wunused-parameter 2022-05-19 14:01:57 +02:00
bb7be9a4cd util/*FifoBuffer: migrate from WritableBuffer to std::span 2022-05-19 14:01:57 +02:00
570755f05a io/BufferedReader: migrate from WritableBuffer to std::span 2022-05-19 13:25:19 +02:00
957d3e51e0 util/{Const,Writable}Buffer: add std::span cast operators 2022-05-19 13:25:02 +02:00
fc6c274c97 pcm/{Dop,Dsd*}: explicitly capture "this"
Implicit capturing is deprecated in C++20.
2022-05-19 13:25:02 +02:00
313b092ba8 system/meson.build: depend on libfmt, not our log.a
Fixes linker error.
2022-05-19 13:25:02 +02:00
0e9e213324 meson.build: switch to C++20 2022-05-19 09:46:59 +02:00
86e6f4fcc0 Merge branch 'v0.23.x' 2022-05-19 09:27:06 +02:00
122db76781 Merge tag 'v0.23.7'
release v0.23.7
2022-05-09 23:14:07 +02:00
601e5e6abc net/AddressInfo: add noexcept 2022-04-26 21:17:01 +02:00
6bacb23002 decoder/ffmpeg: add "noexcept" 2022-04-26 21:07:25 +02:00
5c300a9f1a tag/ReplayGainParser: add "noexcept" 2022-04-26 21:06:26 +02:00
6e1500c251 Merge branch 'v0.23.x' 2022-04-26 21:05:39 +02:00
9e1b24f3a1 input/{Async,Buffering,Thread}InputStream: set VMA name 2022-04-26 20:45:49 +02:00
58a345d346 MusicBuffer: set VMA name
Shows the name in /proc/PID/maps, e.g.:

 7fa57b000000-7fa57c000000 rw-p 00000000 00:00 0                          [anon:MusicBuffer]
2022-04-26 20:44:36 +02:00
7ed67d216b util/HugeAllocator: add SetName() 2022-04-26 20:44:36 +02:00
3ae660ca90 system/VmaName: new library 2022-04-26 20:31:56 +02:00
a742e1fc71 util/PeakBuffer, ...: use [[gnu::]] attributes 2022-04-26 20:31:56 +02:00
ce88dee14d Merge branch 'v0.23.x' 2022-04-26 18:30:34 +02:00
a360475c7b Merge branch 'v0.23.x' 2022-03-26 06:49:51 +01:00
3a3f605a56 decoder/opus: Implement bitrate calculation 2022-03-15 10:34:23 +01:00
407fa2720a Merge tag 'v0.23.6'
release v0.23.6
2022-03-14 18:58:47 +01:00
7293b32025 util/HexFormat: faster implementation without snprintf() 2022-03-14 12:18:52 +01:00
fed8f12863 input/plugins/QobuzClient: pass std::string_view to QueryStringBuilder() 2022-03-14 12:11:46 +01:00
718ae433b2 Merge branch 'build-nits' of git://github.com/sp1ff/MPD 2022-02-27 17:23:17 +01:00
ed65f52f50 Address feedback on PR .
Move the invocation of `find_program` for doxygen into the if
branch & make failure to find the program fatal.
2022-02-27 08:00:12 -08:00
ba1d86ec80 Add (resurrect?) doxygen support.
Added a `doxygen` option to the `doc` build. It makes use of the
already-present but unused file `doxygen.conf.in`.
2022-02-20 10:42:39 -08:00
7661c408a4 Merge branch 'master' of git://github.com/jcorporation/MPD 2022-02-16 05:29:22 +01:00
ee8d5f18ef doc/protocol.rst: fix misnamed priority filter
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1443
2022-02-16 05:29:02 +01:00
de3b9b8232 Update protocol version to 0.24.0 2022-02-15 23:12:06 +01:00
8e99448819 lib/curl/Headers: make the comparison type "transparent" 2022-02-14 18:19:28 +01:00
1e548fb6e3 lib/curl/Headers: central type definition for the header map 2022-02-14 18:19:05 +01:00
fdc0329e64 archive/List: add option to disable archive plugins in mpd.conf
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1384
2022-02-14 17:54:21 +01:00
d3db0400b0 archive/List: convert pointer to reference 2022-02-14 16:43:44 +01:00
b1096a9935 test/{visit_archive,dump_text_file}: add basic config file support (not wired yet) 2022-02-14 16:43:37 +01:00
ab5b6f83fd queue/Print: support sorting by priority 2022-02-14 14:10:33 +01:00
2172aaf1ce song/PrioritySongFilter: new filter
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1412
2022-02-14 14:06:37 +01:00
c68dbc4e5c queue/Queue: add method GetLight() 2022-02-14 13:33:34 +01:00
ec961f26e9 song/DetachedSong: add API docs 2022-02-14 13:27:52 +01:00
c3be961ccf queue/Print: implement sorting 2022-02-14 13:07:13 +01:00
166ce0da5a db/VHelper: move CompareTags() to tag/Sort.cxx 2022-02-14 12:37:05 +01:00
edbaea8df2 db/Selection: refactor IsEmpty() to IsFiltered() 2022-02-14 09:21:32 +01:00
af3a625f64 time/Convert: move GetTimeZoneOffset() to Zone.cxx 2022-02-14 09:21:10 +01:00
11d24a583d command/queue: "playlistfind"/"playlistsearch" have a "window" parameter 2022-02-14 09:12:19 +01:00
e9e3d8c57c queue/Selection: add "window" field 2022-02-14 09:12:18 +01:00
5588291a35 queue/Selection: wrap SongFilter in a new struct 2022-02-14 09:12:18 +01:00
4b41e766c6 queue/Queue{Save,Print}: remove redundant "Queue" prefix from file name 2022-02-14 09:12:06 +01:00
90d52b6501 Merge branch 'v0.23.x' 2022-02-14 09:11:50 +01:00
ad4cf79cc9 tag: new tag "Mood"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1435
2022-02-12 07:50:18 +01:00
4f3828237a Fix DSCP LE value
Correct value is 0x04 since we need to account for the 2 ECN bits.
2022-02-02 16:29:01 +00:00
946cf25732 Merge branch 'v0.23.x' 2022-01-26 14:44:37 +01:00
be72d45356 output/httpd: add config option "dscp"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1401
2022-01-11 20:31:52 +01:00
219c416a1e event/ServerSocket: rename ip_tos to dscp_class and support IPv6 2022-01-11 20:31:52 +01:00
16f7ec9950 net/DscpParser: new library 2022-01-11 20:31:52 +01:00
d79bf853b1 output/httpd: make configuration fields const 2022-01-10 22:59:50 +01:00
1ae6378d85 event/ServerSocket: add ip_tos setting 2022-01-10 22:59:50 +01:00
089a843abd net/SocketDescriptor: add method SetIntOption() 2022-01-10 21:36:15 +01:00
aea4d3c4b0 lib/zlib/GunzipReader: use std::size_t 2022-01-10 16:59:13 +01:00
dda0dfc140 lib/curl/Request: move code from SetupEasy() to Setup.cxx 2021-12-08 20:03:30 +01:00
e0f56b9e2d lib/curl/Request: move code to class CurlResponseHandlerAdapter 2021-12-08 19:51:54 +01:00
3c3c3eeeca MSVC: use winsock2.h instead of sys/time.h for struct timeval 2021-12-08 19:45:03 +01:00
31c7151580 time/Calendar: add DaysInYear() 2021-12-08 19:44:31 +01:00
50a617764a lib/curl/Handler: fix typo 2021-12-08 19:41:39 +01:00
7d67c87a47 io/FileReader: use std::size_t 2021-12-08 19:40:22 +01:00
c072902f23 io/FileOutputStream: merge win32 function Cancel
Win32 had a separate implementation for FileOutputStream::CANCEL Logic
was added to the other platform function, but forgotten in this one.

This merges the functions into one, as only the call for file deletion
is platform specific.
2021-12-08 19:35:11 +01:00
5ad4f3c54b system/EventPipe: include cleanup 2021-12-08 19:32:06 +01:00
0b6055954d thread/AsyncWaiter: new class
Merges some redundant code.
2021-12-08 19:26:57 +01:00
80c177e9a0 io/BufferedOutputStream: add missing char* cast 2021-12-07 12:07:13 +01:00
cdcef49eef lib/curl/Request: add constructor with CurlEasy parameter 2021-12-07 12:01:09 +01:00
9e18aafccc lib/curl/Request: use std::size_t 2021-12-07 12:00:12 +01:00
f7346c1d78 lib/curl/Request: move code to SetupEasy() 2021-12-07 11:57:42 +01:00
b709401814 lib/curl/Request: add API docs 2021-12-07 11:56:45 +01:00
4074db5f50 io/BufferedReader: use std::size_t 2021-12-07 11:54:11 +01:00
8c6bc02bf7 io/BufferedOutputStream: use std::byte 2021-12-07 11:47:45 +01:00
35c11afd54 player/Thread: add option "mixramp_analyzer" 2021-12-06 23:06:08 +01:00
c884e2f285 config/PlayerConfig: default buffer size is 8 MB
Computers are getting more and more RAM, and 8 MB is rarely ever
noticable, but allows longer MixRamp-assisted cross-fading.
2021-12-06 23:05:45 +01:00
b6ba17a865 Merge branch 'v0.23.x' 2021-12-06 21:32:48 +01:00
713c7585b5 pcm/MixRampAnalyzer: a MixRamp implementation 2021-12-06 21:09:28 +01:00
f12c25b7ae pcm/ReplayGainAnalyzer: new library 2021-12-06 21:06:19 +01:00
0a54b987a1 test/run_filter: move ReadFrames() to separate source 2021-12-06 10:31:52 +01:00
2240327286 ReplayGainInfo: move to tag/ 2021-12-06 09:28:36 +01:00
866e7ff3ce config/PlayerConfig: move code to functions 2021-12-06 09:14:36 +01:00
2cafbb2aba player/CrossFade: move code to CanCrossFade() 2021-12-03 23:45:34 +01:00
b78c64376f player/Thread: move code to CheckCrossFade() 2021-12-03 23:32:41 +01:00
2518612b1b player/CrossFade: add method IsMixRampEnabled() 2021-12-03 23:22:55 +01:00
dda521a150 ReplayGain{Config,Global}: move to config/ 2021-12-03 23:08:16 +01:00
95a155b10d Partition: pass configuration as struct 2021-12-03 23:03:41 +01:00
2384a240e0 increment version number to 0.24 2021-12-03 23:01:43 +01:00
1951 changed files with 36098 additions and 49727 deletions
.github
.gitignore.readthedocs.yaml.travis.ymlAUTHORS
LICENSES
NEWSREADME.md
android
build
doc
meson.buildmeson_options.txt
python/build
src
BulkEdit.hxxChrono.hxxCommandLine.cxxCommandLine.hxxConsumeMode.cxxConsumeMode.hxxGitVersion.cxxGitVersion.hxxIdle.cxxIdle.hxxIdleFlags.cxxInstance.cxxInstance.hxxListen.cxxListen.hxxLocateUri.cxxLocateUri.hxxLog.cxxLog.hxxLogBackend.cxxLogBackend.hxxLogInit.cxxLogInit.hxxLogLevel.hxxMain.cxxMain.hxxMapper.cxxMapper.hxxMusicBuffer.cxxMusicBuffer.hxxMusicChunk.cxxMusicChunk.hxxMusicChunkPtr.cxxMusicChunkPtr.hxxMusicPipe.cxxMusicPipe.hxxPartition.cxxPartition.hxxPermission.cxxPermission.hxxPlaylistDatabase.cxxPlaylistDatabase.hxxPlaylistError.cxxPlaylistError.hxxPlaylistFile.cxxPlaylistFile.hxxPlaylistPrint.cxxPlaylistPrint.hxxPlaylistSave.cxxPlaylistSave.hxxPluginUnavailable.hxxRemoteTagCache.cxxRemoteTagCache.hxxRemoteTagCacheHandler.hxxReplayGainConfig.hxxReplayGainGlobal.cxxReplayGainGlobal.hxxReplayGainInfo.cxxReplayGainMode.cxxReplayGainMode.hxxSingleMode.cxxSingleMode.hxxSongLoader.cxxSongLoader.hxxSongPrint.cxxSongPrint.hxxSongSave.cxxSongSave.hxxSongUpdate.cxxStateFile.cxxStateFile.hxxStateFileConfig.cxxStateFileConfig.hxxStats.cxxStats.hxxTagAny.cxxTagAny.hxxTagArchive.cxxTagArchive.hxxTagFile.cxxTagFile.hxxTagPrint.cxxTagPrint.hxxTagSave.cxxTagSave.hxxTagStream.cxxTagStream.hxxTimePrint.cxxTimePrint.hxx
android
apple
archive
client
cmdline
command
config
db
decoder
Bridge.cxxBridge.hxxClient.hxxCommand.hxxControl.cxxControl.hxxDecoderAPI.cxxDecoderAPI.hxxDecoderBuffer.cxxDecoderBuffer.hxxDecoderList.cxxDecoderList.hxxDecoderPlugin.cxxDecoderPlugin.hxxDecoderPrint.cxxDecoderPrint.hxxDomain.cxxDomain.hxxReader.cxxReader.hxxThread.cxx
plugins
encoder
event
filter
fs
haiku
input
AsyncInputStream.cxxAsyncInputStream.hxxBufferedInputStream.cxxBufferedInputStream.hxxBufferingInputStream.cxxBufferingInputStream.hxxCondHandler.hxxError.cxxError.hxxFailingInputStream.hxxHandler.hxxIcyInputStream.cxxIcyInputStream.hxxInit.cxxInit.hxxInputPlugin.cxxInputPlugin.hxxInputStream.cxxInputStream.hxxLastInputStream.cxxLastInputStream.hxxLocalOpen.cxxLocalOpen.hxxMaybeBufferedInputStream.cxxMaybeBufferedInputStream.hxxMemoryInputStream.cxxMemoryInputStream.hxxOffset.hxxOpen.cxxProxyInputStream.cxxProxyInputStream.hxxPtr.hxxReader.cxxReader.hxxRegistry.cxxRegistry.hxxRemoteTagScanner.hxxRewindInputStream.cxxRewindInputStream.hxxScanTags.cxxScanTags.hxxTextInputStream.cxxTextInputStream.hxxThreadInputStream.cxxThreadInputStream.hxxWaitReady.cxxWaitReady.hxx
cache
meson.build
plugins
io
java
lib
alsa
avahi
cdio
chromaprint
crypto
curl
dbus
expat
ffmpeg
fmt
gcrypt
icu
jack
nfs
oss
pcre
pipewire
pulse
smbclient
sqlite
systemd
upnp
xiph
yajl
zlib
ls.cxxls.hxx
mixer
neighbor
net
open.h
output
Client.hxxControl.cxxControl.hxxDefaults.cxxDefaults.hxxDomain.cxxDomain.hxxError.hxxFiltered.cxxFiltered.hxxFinish.cxxInit.cxxInterface.cxxInterface.hxxMultipleOutputs.cxxMultipleOutputs.hxxOutputAPI.hxxOutputCommand.cxxOutputCommand.hxxOutputPlugin.cxxOutputPlugin.hxxPrint.cxxPrint.hxxRegistry.cxxRegistry.hxxSharedPipeConsumer.cxxSharedPipeConsumer.hxxSource.cxxSource.hxxState.cxxState.hxxThread.cxxTimer.cxxTimer.hxxmeson.build
plugins
pcm
player
playlist
protocol
queue
song
sticker
storage
system
tag
thread
time
unix
util
ASCII.hxxAllocatedArray.hxxAllocatedString.hxxBindMethod.hxxBitReverse.cxxBitReverse.hxxByteOrder.hxxByteReverse.cxxByteReverse.hxxCNumberParser.hxxCast.hxxCharUtil.hxxCircularBuffer.hxxClamp.hxxCompiler.hConcepts.hxxConstBuffer.hxxCopyConst.hxxDeleteDisposer.hxxDereferenceIterator.hxxDisposablePointer.hxxDivideString.cxxDivideString.hxxDomain.hxxDynamicFifoBuffer.hxxException.cxxException.hxxFilteredContainer.hxxForeignFifoBuffer.hxxFormatString.cxxFormatString.hxxGenerateArray.hxxHexFormat.cxxHexFormat.hxxHugeAllocator.cxxHugeAllocator.hxxIntrusiveForwardList.hxxIntrusiveHashSet.hxxIntrusiveHookMode.hxxIntrusiveList.hxxIntrusiveTreeSet.hxxIterableSplitString.hxxLazyRandomEngine.cxxLazyRandomEngine.hxxManual.hxxMath.hxxMemberPointer.hxxMimeType.cxxMimeType.hxxNumberParser.cxxNumberParser.hxxOffsetPointer.hxxOptionParser.hxxOptionalCounter.hxxOptionalField.hxxPackedBigEndian.hxxPackedLittleEndian.hxxPeakBuffer.cxxPeakBuffer.hxxPrintException.cxxPrintException.hxxRecursiveMap.hxxRedBlackTree.hxxReusableArray.hxxRingBuffer.hxxRoundPowerOfTwo.hxxRuntimeError.hxxScopeExit.hxxSerial.cxxSerial.hxxSliceBuffer.hxxSortList.hxxSpanCast.hxxSparseBuffer.cxxSparseBuffer.hxxSplitString.cxxSplitString.hxxStaticFifoBuffer.hxxStaticVector.hxxStringAPI.hxxStringBuffer.hxxStringCompare.cxxStringCompare.hxxStringFormat.hxxStringPointer.hxxStringSplit.hxxStringStrip.cxxStringStrip.hxxStringUtil.cxxStringUtil.hxxStringVerify.hxxStringView.cxxStringView.hxxTStringView.hxxTagStructs.hxxTemplateString.hxxTerminatedArray.hxxTextFile.hxxTokenizer.cxxTokenizer.hxxTransformN.hxxTruncateString.cxxTruncateString.hxxUTF8.cxxUTF8.hxxUriExtract.cxxUriExtract.hxxUriQueryParser.cxxUriQueryParser.hxxUriRelative.cxxUriRelative.hxxUriUtil.cxxUriUtil.hxxVarSize.hxxWCharUtil.hxxWStringAPI.hxxWStringCompare.cxxWStringCompare.hxxWStringView.hxxWritableBuffer.hxxdjb_hash.hxxformat.cformat.hmeson.build
win32
zeroconf
subprojects
systemd
test
ConfigGlue.hxxContainerScan.cxxDumpDatabase.cxxDumpDecoderClient.cxxDumpDecoderClient.hxxDumpOgg.cxxLoadDatabase.cxxMakeTag.hxxNullMixerListener.hxxParseSongFilter.cxxReadApeTags.cxxReadFrames.cxxReadFrames.hxxRunChromaprint.cxxRunCurl.cxxRunMixRampAnalyzer.cxxRunReplayGainAnalyzer.cxxRunZeroconf.cxxShutdownHandler.cxxShutdownHandler.hxxTestAudioFormat.cxxTestRewindInputStream.cxxTestStringFilter.cxxTestTagSongFilter.cxxWriteFile.cxxdump_playlist.cxxdump_rva2.cxxdump_text_file.cxx
fs
fuzzer
meson.build
net
playlist
read_conf.cxxread_mixer.cxxread_tags.cxxrun_convert.cxxrun_decoder.cxxrun_encoder.cxxrun_filter.cxxrun_gunzip.cxxrun_gzip.cxxrun_inotify.cxxrun_input.cxxrun_neighbor_explorer.cxxrun_normalize.cxxrun_output.cxxrun_resolver.cxxrun_storage.cxxsoftware_volume.cxx
tag
test_icy_parser.cxxtest_pcm_channels.cxxtest_pcm_dither.cxxtest_pcm_export.cxxtest_pcm_format.cxxtest_pcm_interleave.cxxtest_pcm_mix.cxxtest_pcm_pack.cxxtest_pcm_util.hxxtest_pcm_volume.cxxtest_queue_priority.cxxtest_translate_song.cxxtest_vorbis_encoder.cxx
time
util
visit_archive.cxx
win32

@ -24,3 +24,4 @@ about: Create a bug report
## Log
<!-- Paste relevant portions of the log file here (--verbose) -->
<!-- If MPD has crashed, include a backtrace (see https://mpd.readthedocs.io/en/stable/user.html#mpd-crashes) -->

6
.github/dependabot.yml vendored Normal file

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

@ -3,6 +3,11 @@ on:
workflow_dispatch:
push:
paths-ignore:
- 'AUTHORS'
- 'COPYING'
- 'LICENSES/**'
- 'NEWS'
- 'README.md'
- 'android/**'
- 'build/**'
- 'doc/**'
@ -15,6 +20,11 @@ on:
- v0.23.x
pull_request:
paths-ignore:
- 'AUTHORS'
- 'COPYING'
- 'LICENSES/**'
- 'NEWS'
- 'README.md'
- 'android/**'
- 'build/**'
- 'doc/**'
@ -26,24 +36,52 @@ on:
- master
- v0.23.x
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
build-linux:
runs-on: ubuntu-latest
strategy:
matrix:
compiler: [gcc14, gcc12, clang]
include:
- compiler: gcc14
os: ubuntu-24.04
cc: gcc-14
cxx: g++-14
packages: g++-14
meson_options:
- compiler: gcc12
os: ubuntu-24.04
cc: gcc-12
cxx: g++-12
packages: g++-12
meson_options:
- compiler: clang
os: ubuntu-24.04
cc: clang
cxx: clang++
packages: clang
meson_options: --force-fallback-for=fmt,gtest
runs-on: ${{ matrix.os }}
env:
CC: 'ccache gcc-10'
CXX: 'ccache g++-10'
CC: ccache ${{ matrix.cc }}
CXX: ccache ${{ matrix.cxx }}
steps:
- id: checkout
uses: actions/checkout@v2
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: linux
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
g++-10 libfmt-dev libboost-dev \
${{ matrix.packages }} \
meson \
ccache \
libfmt-dev \
libgtest-dev \
libpcre2-dev \
libsystemd-dev libdbus-1-dev \
@ -73,83 +111,225 @@ jobs:
libchromaprint-dev \
libgcrypt20-dev
- name: Full Build
uses: BSFishy/meson-build@v1.0.3
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
action: build
directory: output/full
setup-options: -Ddocumentation=disabled -Dtest=true -Dsystemd=enabled -Dpcre=enabled
options: --verbose
meson-version: 0.56.0
key: ${{ matrix.os }}-${{ matrix.compiler }}
- name: Configure
run: |
meson setup \
-Ddocumentation=disabled \
-Dtest=true \
-Dsystemd=enabled \
-Dpcre=enabled \
--wrap-mode nofallback \
${{ matrix.meson_options }} \
output/full
- name: Build
run: meson compile -C output/full --verbose
- 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
run: meson test -C output/full --print-errorlogs
- 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
- name: Configure Mini
run: |
meson setup \
-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 \
--wrap-mode nofallback \
${{ matrix.meson_options }} \
output/mini
- name: Build Mini
run: meson compile -C output/mini --verbose
- name: Unit Tests Mini
run: meson test -C output/mini --print-errorlogs
build-macos:
runs-on: macos-latest
strategy:
matrix:
compiler: [clang]
include:
- compiler: clang
os: macos-latest
cc: clang
cxx: clang++
brew_packages: >
meson ninja
pkgconf
ccache
expat
fmt
googletest
pcre2
icu4c
ffmpeg
libnfs
libupnp
libid3tag
chromaprint
libsamplerate
libsoxr
flac
opus
libvorbis
faad2
sqlite
wavpack
libmpdclient
meson_options: --force-fallback-for=fmt,gtest
runs-on: ${{ matrix.os }}
env:
CC: ccache ${{ matrix.cc }}
CXX: ccache ${{ matrix.cxx }}
steps:
- id: checkout
uses: actions/checkout@v2
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: macos
- uses: actions/setup-python@v1
uses: actions/checkout@v4
- name: Install dependencies
run: |
brew update
brew install \
meson ninja \
fmt \
boost \
googletest \
icu4c \
ffmpeg \
libnfs \
yajl \
libupnp \
libid3tag \
chromaprint \
libsamplerate \
libsoxr \
flac \
opus \
libvorbis \
faad2 \
wavpack \
libmpdclient
${{ matrix.brew_packages }}
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ matrix.os }}-${{ matrix.compiler }}
- name: Configure
run: |
meson setup \
-Ddocumentation=disabled \
-Dtest=true \
-Dpcre=enabled \
--wrap-mode nofallback \
${{ matrix.meson_options }} \
output/full
- 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
run: meson compile -C output/full --verbose
- name: Unit Tests
uses: BSFishy/meson-build@v1.0.3
run: meson test -C output/full --print-errorlogs
- name: Configure Mini
run: |
meson setup \
-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 \
--wrap-mode nofallback \
${{ matrix.meson_options }} \
output/mini
- name: Build Mini
run: meson compile -C output/mini --verbose
- name: Unit Tests Mini
run: meson test -C output/mini --print-errorlogs
build-msys2:
strategy:
matrix:
platform: ['MINGW64', 'UCRT64']
defaults:
run:
shell: msys2 {0}
runs-on: windows-latest
steps:
- id: checkout
uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
action: test
directory: output
setup-options: -Ddocumentation=disabled -Dtest=true
options: --verbose
meson-version: 0.56.0
msystem: ${{matrix.platform}}
pacboy: >-
cc:p
ccache:p
cmake:p
dbus:p
faad2:p
ffmpeg:p
fmt:p
flac:p
gtest:p
jack2:p
libao:p
libid3tag:p
libmad:p
libmpcdec:p
libopenmpt:p
libsamplerate:p
libshout:p
libsndfile:p
libsoxr:p
libvorbis:p
meson:p
ninja:p
opus:p
pulseaudio:p
shine:p
twolame:p
yajl:p
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ matrix.platform }}
- name: Configure
run: |
meson setup \
-Dbzip2=disabled \
-Dcdio_paranoia=disabled \
-Dchromaprint=disabled \
-Ddocumentation=disabled \
-Dfluidsynth=disabled \
-Dicu=disabled \
-Diso9660=disabled \
-Dmikmod=disabled \
-Dmpg123=disabled \
-Dnfs=disabled \
-Dsidplay=disabled \
-Dudisks=disabled \
-Dupnp=disabled \
-Dwavpack=disabled \
-Dzzip=disabled \
-Dtest=true \
"${{github.workspace}}/build"
- name: Build
run: meson compile -C "${{github.workspace}}/build" --verbose
- name: Unit Tests
run: meson test -C "${{github.workspace}}/build" --print-errorlogs

68
.github/workflows/build_android.yml vendored Normal file

@ -0,0 +1,68 @@
---
on:
workflow_dispatch:
push:
paths-ignore:
- 'AUTHORS'
- 'COPYING'
- 'LICENSES/**'
- 'NEWS'
- 'README.md'
- 'build/**'
- 'doc/**'
- 'subprojects/**'
- 'systemd/**'
- 'win32/**'
branches:
- master
pull_request:
paths-ignore:
- 'AUTHORS'
- 'COPYING'
- 'LICENSES/**'
- 'NEWS'
- 'README.md'
- 'build/**'
- 'doc/**'
- 'subprojects/**'
- 'systemd/**'
- 'win32/**'
branches:
- master
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
build-android:
runs-on: ubuntu-24.04
steps:
- id: checkout
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
meson \
ccache \
quilt
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: android
- name: Build
run: |
mkdir -p output/android
cd ./output/android
../../android/build.py $ANDROID_SDK_ROOT $ANDROID_NDK_HOME arm64-v8a \
--buildtype=debugoptimized -Db_ndebug=true \
-Dwrap_mode=forcefallback
cd -
cd ./android
export JAVA_HOME=$JAVA_HOME_17_X64
./gradlew assembleDebug

8
.gitignore vendored

@ -1,11 +1,3 @@
*~
.#*
.stgit*
/output/
__pycache__/
/.clangd/
/compile_commands.json

19
.readthedocs.yaml Normal file

@ -0,0 +1,19 @@
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.12"
python:
install:
- requirements: "doc/requirements.txt"
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: doc/conf.py

@ -1,117 +0,0 @@
language: cpp
jobs:
include:
# Ubuntu Focal (20.04) with GCC 9.3
- os: linux
dist: focal
addons:
apt:
packages:
- meson
- libgtest-dev
- libboost-dev
- libfmt-dev
# Ubuntu Focal (20.04) with GCC 9.3 on big-endian
- os: linux
arch: s390x
dist: focal
addons:
apt:
packages:
- meson
- libgtest-dev
- libboost-dev
- libfmt-dev
# Ubuntu Focal (20.04) with GCC 9.3 on ARM64
- os: linux
arch: arm64
dist: focal
addons:
apt:
packages:
- meson
- libgtest-dev
- libboost-dev
- libfmt-dev
# Ubuntu Trusty (16.04) with GCC 8
- os: linux
dist: trusty
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:mhier/libboost-latest'
- sourceline: 'ppa:ricotz/toolchain'
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
packages:
- g++-8
- libgtest-dev
- boost1.67
- python3.6
- python3-urllib3
- ninja-build
before_install:
- wget https://bootstrap.pypa.io/get-pip.py
- /usr/bin/python3.6 get-pip.py --user --no-cache-dir
install:
- /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson --no-cache-dir
env:
# use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068
- MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH"
- os: osx
osx_image: xcode11.6
addons:
homebrew:
packages:
- ccache
- meson
- fmt
- googletest
- icu4c
- ffmpeg
- libnfs
- yajl
- libupnp
- libid3tag
- chromaprint
- libsamplerate
- libsoxr
# libzzip appears to be broken on Homebrew: "ld: library not found for -lzzip"
#- libzzip
- flac
- opus
- libvorbis
- faad2
- wavpack
- libmpdclient
env:
- MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH HOMEBREW_NO_ANALYTICS=1"
cache:
apt: true
ccache: true
directories:
- $HOME/Library/Caches/Homebrew
before_cache:
- test "$TRAVIS_OS_NAME" != "osx" || brew cleanup
before_install:
- eval "${MATRIX_EVAL}"
install:
before_script:
- ccache -s
script:
- eval "${MATRIX_EVAL}"
- OPTIONS="-Dtest=true"
- meson . output --werror $OPTIONS
- ninja -C output -v test
- ccache -s

@ -1,5 +1,5 @@
Music Player Daemon - http://www.musicpd.org
Copyright 2003-2021 The Music Player Daemon Project
Copyright 2003-2025 The Music Player Daemon Project
The following people have contributed code to MPD:

@ -0,0 +1,9 @@
Copyright (c) <year> <owner>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,117 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice

8
LICENSES/ISC.txt Normal file

@ -0,0 +1,8 @@
ISC License:
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
Copyright (c) 1995-2003 by Internet Software Consortium
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

175
LICENSES/LGPL-2.1-only.txt Normal file

@ -0,0 +1,175 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.]
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.
To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others.
Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs.
When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library.
We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances.
For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system.
Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.
(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.
In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices.
Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.
If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:
a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.
e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.
7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.
b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License.
11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License).
To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
one line to give the library's name and an idea of what it does.
Copyright (C) year name of author
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in
the library `Frob' (a library for tweaking knobs) written
by James Random Hacker.
signature of Ty Coon, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

93
NEWS

@ -1,3 +1,94 @@
ver 0.24.1 (not yet released)
* output
- sndio: fix rounding error in volume calculation
* log: include year in time stamp
* macOS: implement standard directories
* fix build failure in the "id3tag" Meson subproject
* doc: use "sphinx_rtd_theme" only if it is installed
ver 0.24 (2025/03/11)
* protocol
- new command "searchcount" (case-insensitive "count")
- "playlistfind"/"playlistsearch" have "sort" and "window" parameters
- allow range in "playlistmove"
- "save" can append to or replace an existing playlist
- filter "prio" (for "playlistfind"/"playlistsearch")
- limit "player" idle events to the current partition
- operator "starts_with"
- show PCRE support in "config" response
- apply Unicode normalization to case-insensitive filter expressions
- stickers on playlists and some tag types
- new commands "stickernames", "stickertypes", "stickernamestypes", "playlistlength", "searchplaylist", "protocol"
- new "search"/"find" filter "added-since"
- allow range in listplaylist and listplaylistinfo
- "sticker find" supports sort and window parameter and new sticker compare operators "eq", "lt", "gt", "contains" and "starts_with"
- consume only idle flags that were subscribed to
- volume command is no longer deprecated
- new "available" and "reset" subcommands for tagtypes
- searching stored playlists respond now with song position
- new sticker subcommand "inc" and "dec"
* database
- attribute "added" shows when each song was added to the database
- proxy: require MPD 0.21 or later
- proxy: require libmpdclient 2.15 or later
* archive
- add option to disable archive plugins in mpd.conf
* storage
- curl: optimize database update
- nfs: require libnfs 4.0 or later
- nfs: support libnfs 6 (API version 2)
- nfs: support libnfs URL arguments
* input
- alsa: limit ALSA buffer time to 2 seconds
- alsa: set up a channel map
- alsa: support the alsa-lib 1.2.11 API
- alsa: add option "close_on_pause"
- curl: add "connect_timeout" configuration
* decoder
- ffmpeg: require FFmpeg 4.0 or later
- ffmpeg: query supported demuxers at runtime
- hybrid_dsd: remove
- mpg123: prefer over "mad"
- mpg123: support streaming
- opus: implement bitrate calculation
- sidplay: require libsidplayfp (drop support for the original sidplay)
- wavpack: require libwavpack version 5
- fix MixRamp bug
* resampler
- soxr: require libsoxr 0.1.2 or later
* player
- add option "mixramp_analyzer" to scan MixRamp tags on-the-fly
- "one-shot" consume mode
* tags
- new tags "TitleSort", "Mood", "ShowMovement"
* output
- add option "always_off"
- alsa: require alsa-lib 1.1 or later
- pipewire: map tags "Date" and "Comment"
* switch to C++20
- GCC 12 or clang 14 (or newer) recommended
* static partition configuration
* Windows
- build with libsamplerate
- remove JACK DLL support
* remove Haiku support
* remove Boost dependency
* require libfmt 9 or later
* documentation: switch to sphinx-rtd-theme
* require Meson 1.0
ver 0.23.17 (2025/01/29)
* protocol
- "albumart" tries to send larger chunks if available
- explicitly disallow "idle" and "noidle" in command lists
* storage
- nfs: require libnfs 4.0 or later
* database
- inotify: trigger update after symlink was created
* decoder
- ffmpeg: prefer over sndfile and audiofile for its DTS-WAV support
* support libfmt 11.1
ver 0.23.16 (2024/12/03)
* database
- fix integer overflows with 64-bit inode numbers
@ -958,7 +1049,7 @@ ver 0.20.10 (2017/08/24)
* decoder
- ffmpeg: support MusicBrainz ID3v2 tags
* tags
- aiff: fix FORM chunk size endianess (is big-endian)
- aiff: fix FORM chunk size endianness (is big-endian)
* mixer
- osx: add a mixer for OSX.
* fix crash when resuming playback before decoder is ready

@ -12,15 +12,15 @@ For basic installation instructions
# Users
- [Manual](http://www.musicpd.org/doc/user/)
- [Forum](http://forum.musicpd.org/)
- [Manual](https://mpd.readthedocs.io/en/stable/user.html)
- [Forum](https://github.com/MusicPlayerDaemon/MPD/discussions)
- [IRC](ircs://irc.libera.chat:6697/#mpd)
- [Bug tracker](https://github.com/MusicPlayerDaemon/MPD/issues/)
# Developers
- [Protocol specification](http://www.musicpd.org/doc/protocol/)
- [Developer manual](http://www.musicpd.org/doc/developer/)
- [Protocol specification](https://mpd.readthedocs.io/en/latest/protocol.html)
- [Developer manual](https://mpd.readthedocs.io/en/latest/developer.html)
# Legal

24
android/.gitignore vendored Normal file

@ -0,0 +1,24 @@
*.iml
.gradle
/local.properties
## ignoring .idea completely
# until a good reason emerges not to
/.idea
##--
## moved the following into .idea/.gitignore
#/.idea/caches
#/.idea/libraries
#/.idea/modules.xml
#/.idea/workspace.xml
#/.idea/navEditor.xml
#/.idea/assetWizardSettings.xml
## --
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
# both were used: different spelling
app/src/main/jnilibs/
app/src/main/jniLibs/

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="74"
android:versionName="0.23.16">
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30"/>
<uses-feature android:name="android.software.leanback"
android:required="false" />
<uses-feature android:name="android.hardware.touchscreen"
android:required="false" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<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"
android:label="@string/app_name">
<activity android:name=".Settings"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Settings"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".Receiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name=".Main" android:process=":main"/>
</application>
</manifest>

@ -0,0 +1,8 @@
MPD for Android Privacy Policy
==============================
Music Player Daemon is an open source project currently maintained by
`Max Kellermann <mailto:max.kellermann+googleplay@gmail.com>`__.
Music Player Daemon does not access, collect, use or share any
personal or sensitive user data.

49
android/README.md Normal file

@ -0,0 +1,49 @@
# Android
Notes and resources for MPD android maintainers.
## Build
See [Compiling for Android](https://github.com/MusicPlayerDaemon/MPD/blob/45cb098cd765af12316f8dca5635ef10a852e013/doc/user.rst#compiling-for-android)
## Android studio
### Version control
git ignoring .idea directory completely until a good reason emerges not to
* [How to manage projects under Version Control Systems (jetbrains.com)](https://intellij-support.jetbrains.com/hc/en-us/articles/206544839-How-to-manage-projects-under-Version-Control-Systems)
* [gradle.xml should work like workspace.xml? (jetbrains.com)](https://youtrack.jetbrains.com/issue/IDEA-55923)
### Native libraries
* [Include prebuilt native libraries (developer.android.com)](https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs)
## Permissions
### Files access
The required permission depends on android SDK version:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
Manifest.permission.READ_MEDIA_AUDIO
else
Manifest.permission.READ_EXTERNAL_STORAGE
### Permission request
[Request runtime permissions](https://developer.android.com/training/permissions/requesting)
Since Android 6.0 (API level 23):
Android will ignore permission request and will not show the request dialog
if the user's action implies "don't ask again."
This leaves the app in a crippled state and the user confused.
Google says "don't try to convince the user", so it returns false for `shouldShowRequestPermissionRationale`.
To help the user proceed, we show the `Request permission` button only if `shouldShowRequestPermissionRationale == true`
because there's a good chance the permission request dialog will not be ignored.
If `shouldShowRequestPermissionRationale == false` we instead show the "rationale" message and a button to open
the app info dialog where the user can explicitly grand the permission.

@ -1,21 +0,0 @@
#!/bin/sh -e
S=`dirname "$0"`
ANDROID_ABI=$1
STRIP=$2
ZIP=$3
UNSIGNED_APK=$4
LIBMPD_SO=$5
CLASSES_DEX=$6
RESOURCES_APK=$7
D=`dirname "$UNSIGNED_APK"`
rm -rf "$D/apk"
mkdir -p "$D/apk/lib/$ANDROID_ABI"
"$STRIP" "$LIBMPD_SO" -o "$D/apk/lib/$ANDROID_ABI/`basename $LIBMPD_SO`"
cp "$CLASSES_DEX" "$D/apk/"
cp "$RESOURCES_APK" "$UNSIGNED_APK"
cd "$D/apk"
exec zip -q -r -X "../`basename $UNSIGNED_APK`" .

@ -1,58 +0,0 @@
unsigned_apk = custom_target(
'mpd-unsigned.apk',
output: 'mpd-unsigned.apk',
input: [mpd, classes_dex, resources_apk[0]],
command: [
join_paths(meson.current_source_dir(), 'make-unsigned-apk.sh'),
android_abi,
get_option('android_strip'),
zip,
'@OUTPUT0@',
'@INPUT@',
],
)
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: aligned_apk,
command: [
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
)
endif
if get_option('android_keystore') != '' and get_option('android_keyalias') != '' and get_option('android_keypass') != ''
unaligned_apk = custom_target(
'mpd.apk',
output: 'mpd.apk',
input: aligned_apk,
command: [
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'),
],
)
endif

1
android/app/.gitignore vendored Normal file

@ -0,0 +1 @@
/build

@ -0,0 +1,128 @@
plugins {
id("com.google.devtools.ksp")
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.dagger.hilt.android)
}
android {
namespace = "org.musicpd"
compileSdk = 35
defaultConfig {
applicationId = "org.musicpd"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
vectorDrawables {
useSupportLibrary = true
}
}
buildFeatures {
aidl = true
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.10"
}
buildTypes {
debug {
isMinifyEnabled = false
}
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
// flavors
flavorDimensions += "base"
productFlavors {
create("fail-test") {
// To test System.loadLibrary("mpd") failure
// exclude the native lib from the package
packaging {
jniLibs {
// it appears the 'excludes' is applied to all flavors
// even if it's only inside this flavor.
// this filters by task name to apply the exclusion only
// for this flavor name.
// (clearing the 'abiFilters' will only create a universal apk
// with all of the abi versions)
gradle.startParameter.getTaskNames().forEach { task ->
if (task.contains("fail-test", ignoreCase = true)) {
println("NOTICE: excluding libmpd.so from package $task for testing")
excludes += "**/libmpd.so"
}
}
}
}
}
create("arm64-v8a") {
ndk {
// ABI to include in package
//noinspection ChromeOsAbiSupport
abiFilters += listOf("arm64-v8a")
}
}
create("x86_64") {
ndk {
// ABI to include in package
abiFilters += listOf("x86_64")
}
}
create("universal") {
ndk {
// ABI to include in package
abiFilters += listOf("arm64-v8a", "x86_64")
}
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_9
targetCompatibility = JavaVersion.VERSION_1_9
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_9.toString()
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.material3)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.material.icons.extended)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.compose.settings.ui.m3)
implementation(libs.compose.settings.storage.preferences)
implementation(libs.accompanist.permissions)
implementation(libs.hilt.android)
ksp(libs.dagger.compiler)
ksp(libs.hilt.compiler)
implementation(libs.androidx.media3.session)
// Android Studio Preview support
implementation(libs.androidx.ui.tooling.preview)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
implementation(libs.androidx.appcompat)
}

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="auto"
android:versionCode="73"
android:versionName="0.23.15">
<uses-feature
android:name="android.software.leanback"
android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<application
android:allowBackup="true"
android:banner="@mipmap/ic_banner"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/Theme.MPD"
android:name=".MPDApplication">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".Receiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<receiver android:name=".AutomationReceiver"
android:exported="true">
<intent-filter>
<action android:name="org.musicpd.action.StartService" />
</intent-filter>
<intent-filter>
<action android:name="org.musicpd.action.StopService" />
</intent-filter>
</receiver>
<service
android:name=".Main"
android:foregroundServiceType="mediaPlayback"
/>
</application>
</manifest>

@ -5,5 +5,4 @@ interface IMainCallback
void onStarted();
void onStopped();
void onError(String error);
void onLog(int priority, String msg);
}

Binary file not shown.

After

(image error) Size: 49 KiB

@ -0,0 +1,24 @@
package org.musicpd
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
class AutomationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when(intent.action) {
"org.musicpd.action.StartService" -> {
val wakelock = Preferences.getBoolean(
context,
Preferences.KEY_WAKELOCK, false
)
Main.startService(context, wakelock)
}
"org.musicpd.action.StopService" -> {
context.startService(Intent(context, Main::class.java)
.setAction(Main.SHUTDOWN_ACTION))
}
}
}
}

@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
package org.musicpd;
import android.content.Context;
/**
* Bridge to native code.
*/
public class Bridge {
/* used by jni */
public interface LogListener {
public void onLog(int priority, String msg);
}
public static native void run(Context context, LogListener logListener);
public static native void shutdown();
public static native void pause();
public static native void playPause();
public static native void playNext();
public static native void playPrevious();
}

@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
package org.musicpd
import android.content.Context
import android.os.Build
import android.util.Log
object Loader {
private const val TAG = "Loader"
private var loaded: Boolean = false
private var error: String? = null
private val failReason: String get() = error ?: ""
val isLoaded: Boolean get() = loaded
init {
load()
}
private fun load() {
if (loaded) return
loaded = try {
error = null
System.loadLibrary("mpd")
Log.i(TAG, "mpd lib loaded")
true
} catch (e: Throwable) {
error = e.message ?: e.javaClass.simpleName
Log.e(TAG, "failed to load mpd lib: $failReason")
false
}
}
fun loadFailureMessage(context: Context): String {
return context.getString(
R.string.mpd_load_failure_message,
Build.SUPPORTED_ABIS.joinToString(),
Build.PRODUCT,
Build.FINGERPRINT,
failReason
)
}
}

@ -0,0 +1,9 @@
package org.musicpd
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class MPDApplication : Application() {
}

@ -0,0 +1,76 @@
package org.musicpd;
import android.annotation.SuppressLint;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.media3.common.Player;
import androidx.media3.common.SimpleBasePlayer;
import androidx.media3.common.util.UnstableApi;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Arrays;
import java.util.List;
@UnstableApi
public class MPDPlayer extends SimpleBasePlayer {
List<MediaItemData> placeholderItems;
public MPDPlayer(Looper looper) {
super(looper);
// Dummy items to let us receive next and previous commands
MediaItemData item0 = new MediaItemData.Builder(0)
.build();
MediaItemData item1 = new MediaItemData.Builder(1)
.build();
MediaItemData item2 = new MediaItemData.Builder(2)
.build();
MediaItemData[] items = new MediaItemData[] { item0, item1, item2 };
placeholderItems = Arrays.asList(items);
}
@NonNull
@Override
protected State getState() {
Commands commands = new Commands.Builder().addAll(
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
COMMAND_PLAY_PAUSE
).build();
return new State.Builder()
.setAvailableCommands(commands)
.setPlaybackState(Player.STATE_READY)
.setPlaylist(placeholderItems)
.setCurrentMediaItemIndex(1)
.build();
}
@NonNull
@Override
protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) {
Bridge.playPause();
return Futures.immediateVoidFuture();
}
@NonNull
@SuppressLint("SwitchIntDef")
@Override
protected ListenableFuture<?> handleSeek(int mediaItemIndex, long positionMs, int seekCommand) {
switch (seekCommand) {
case COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM:
case COMMAND_SEEK_TO_PREVIOUS:
Bridge.playPrevious();
break;
case COMMAND_SEEK_TO_NEXT_MEDIA_ITEM:
case COMMAND_SEEK_TO_NEXT:
Bridge.playNext();
break;
}
return Futures.immediateVoidFuture();
}
}

@ -0,0 +1,326 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
package org.musicpd
import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.media.AudioManager
import android.os.Build
import android.os.IBinder
import android.os.Looper
import android.os.PowerManager
import android.os.PowerManager.WakeLock
import android.os.RemoteCallbackList
import android.os.RemoteException
import android.util.Log
import androidx.annotation.OptIn
import androidx.core.app.ServiceCompat
import androidx.media3.common.util.UnstableApi
import androidx.media3.session.MediaSession
import dagger.hilt.android.AndroidEntryPoint
import org.musicpd.Bridge.LogListener
import org.musicpd.data.LoggingRepository
import java.lang.reflect.Constructor
import javax.inject.Inject
@AndroidEntryPoint
class Main : Service(), Runnable {
companion object {
private const val TAG = "Main"
private const val WAKELOCK_TAG = "mpd:wakelockmain"
private const val MAIN_STATUS_ERROR = -1
private const val MAIN_STATUS_STOPPED = 0
private const val MAIN_STATUS_STARTED = 1
private const val MSG_SEND_STATUS = 0
const val SHUTDOWN_ACTION: String = "org.musicpd.action.ShutdownMPD"
/*
* start Main service without any callback
*/
@JvmStatic
fun startService(context: Context, wakelock: Boolean) {
val intent = Intent(context, Main::class.java)
.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)
}
}
private lateinit var mpdApp: MPDApplication
private lateinit var mpdLoader: Loader
private var mThread: Thread? = null
private var mStatus = MAIN_STATUS_STOPPED
private var mAbort = false
private var mError: String? = null
private val mCallbacks = RemoteCallbackList<IMainCallback>()
private val mBinder: IBinder = MainStub(this)
private var mPauseOnHeadphonesDisconnect = false
private var mWakelock: WakeLock? = null
private var mMediaSession: MediaSession? = null
@JvmField
@Inject
var logging: LoggingRepository? = null
internal class MainStub(private val mService: Main) : IMain.Stub() {
override fun start() {
mService.start()
}
override fun stop() {
mService.stop()
}
override fun setPauseOnHeadphonesDisconnect(enabled: Boolean) {
mService.setPauseOnHeadphonesDisconnect(enabled)
}
override fun setWakelockEnabled(enabled: Boolean) {
mService.setWakelockEnabled(enabled)
}
override fun isRunning(): Boolean {
return mService.isRunning
}
override fun registerCallback(cb: IMainCallback) {
mService.registerCallback(cb)
}
override fun unregisterCallback(cb: IMainCallback) {
mService.unregisterCallback(cb)
}
}
override fun onCreate() {
super.onCreate()
mpdLoader = Loader
}
@Synchronized
private fun sendMessage(
@Suppress("SameParameterValue") what: Int,
arg1: Int,
arg2: Int,
obj: Any?
) {
var i = mCallbacks.beginBroadcast()
while (i > 0) {
i--
val cb = mCallbacks.getBroadcastItem(i)
try {
when (what) {
MSG_SEND_STATUS -> when (arg1) {
MAIN_STATUS_ERROR -> cb.onError(obj as String?)
MAIN_STATUS_STOPPED -> cb.onStopped()
MAIN_STATUS_STARTED -> cb.onStarted()
}
}
} catch (ignored: RemoteException) {
}
}
mCallbacks.finishBroadcast()
}
private val mLogListener = LogListener { priority, msg ->
logging?.addLogItem(priority, msg)
}
override fun onBind(intent: Intent): IBinder {
return mBinder
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent?.action == SHUTDOWN_ACTION) {
stop()
} else {
start()
if (intent?.getBooleanExtra(
"wakelock",
false
) == true
) setWakelockEnabled(true)
}
return START_REDELIVER_INTENT
}
override fun run() {
synchronized(this) {
if (mAbort) return
setStatus(MAIN_STATUS_STARTED, null)
}
Bridge.run(this, mLogListener)
setStatus(MAIN_STATUS_STOPPED, null)
}
@Synchronized
private fun setStatus(status: Int, error: String?) {
mStatus = status
mError = error
sendMessage(MSG_SEND_STATUS, mStatus, 0, mError)
}
private fun createNotificationBuilderWithChannel(): Notification.Builder? {
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as? NotificationManager
?: return null
val id = "org.musicpd"
val name = "MPD service"
val importance = 3 /* NotificationManager.IMPORTANCE_DEFAULT */
try {
val ncClass = Class.forName("android.app.NotificationChannel")
val ncCtor = ncClass.getConstructor(
String::class.java,
CharSequence::class.java,
Int::class.javaPrimitiveType
)
val nc = ncCtor.newInstance(id, name, importance)
val nmCreateNotificationChannelMethod =
NotificationManager::class.java.getMethod("createNotificationChannel", ncClass)
nmCreateNotificationChannelMethod.invoke(notificationManager, nc)
val nbCtor: Constructor<*> = Notification.Builder::class.java.getConstructor(
Context::class.java, String::class.java
)
return nbCtor.newInstance(this, id) as Notification.Builder
} catch (e: Exception) {
Log.e(TAG, "error creating the NotificationChannel", e)
return null
}
}
@OptIn(markerClass = [UnstableApi::class])
private fun start() {
if (mThread != null) return
val filter = IntentFilter()
filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (!mPauseOnHeadphonesDisconnect) return
if (intent.action === AudioManager.ACTION_AUDIO_BECOMING_NOISY) pause()
}
}, filter)
val mainIntent = Intent(this, MainActivity::class.java)
mainIntent.setAction("android.intent.action.MAIN")
mainIntent.addCategory("android.intent.category.LAUNCHER")
val contentIntent = PendingIntent.getActivity(
this, 0,
mainIntent, PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val nBuilder: Notification.Builder?
if (Build.VERSION.SDK_INT >= 26 /* Build.VERSION_CODES.O */) {
nBuilder = createNotificationBuilderWithChannel()
if (nBuilder == null) return
} else nBuilder = Notification.Builder(this)
val notification =
nBuilder.setContentTitle(getText(R.string.notification_title_mpd_running))
.setContentText(getText(R.string.notification_text_mpd_running))
.setSmallIcon(R.drawable.notification_icon)
.setContentIntent(contentIntent)
.build()
if (mpdLoader.isLoaded) {
mThread = Thread(this).apply { start() }
}
val player = MPDPlayer(Looper.getMainLooper())
mMediaSession = MediaSession.Builder(this, player).build()
startForeground(R.string.notification_title_mpd_running, notification)
startService(Intent(this, Main::class.java))
}
private fun stop() {
mMediaSession?.let {
it.release()
mMediaSession = null
}
mThread?.let { thread ->
if (thread.isAlive) {
synchronized(this) {
if (mStatus == MAIN_STATUS_STARTED) Bridge.shutdown()
else mAbort = true
}
}
try {
thread.join()
mThread = null
mAbort = false
} catch (ie: InterruptedException) {
Log.e(TAG, "failed to join", ie)
}
}
setWakelockEnabled(false)
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
stopSelf()
}
private fun pause() {
if (mThread?.isAlive == true) {
synchronized(this) {
if (mStatus == MAIN_STATUS_STARTED) Bridge.pause()
}
}
}
private fun setPauseOnHeadphonesDisconnect(enabled: Boolean) {
mPauseOnHeadphonesDisconnect = enabled
}
private fun setWakelockEnabled(enabled: Boolean) {
if (enabled) {
val wakeLock =
mWakelock ?: run {
val pm = getSystemService(POWER_SERVICE) as PowerManager
pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG).also {
mWakelock = it
}
}
wakeLock.acquire(10 * 60 * 1000L /*10 minutes*/)
Log.d(TAG, "Wakelock acquired")
} else {
mWakelock?.let {
it.release()
mWakelock = null
}
Log.d(TAG, "Wakelock released")
}
}
private val isRunning: Boolean
get() = mThread?.isAlive == true
private fun registerCallback(cb: IMainCallback?) {
if (cb != null) {
mCallbacks.register(cb)
sendMessage(MSG_SEND_STATUS, mStatus, 0, mError)
}
}
private fun unregisterCallback(cb: IMainCallback?) {
if (cb != null) {
mCallbacks.unregister(cb)
}
}
}

@ -0,0 +1,57 @@
package org.musicpd
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.material3.MaterialTheme
import androidx.core.view.WindowCompat
import dagger.hilt.android.AndroidEntryPoint
import org.musicpd.ui.MPDApp
import org.musicpd.ui.SettingsViewModel
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val settingsViewModel: SettingsViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
MaterialTheme {
MPDApp(settingsViewModel = settingsViewModel)
}
}
}
private fun connectClient() {
val client = MainServiceClient(this, object : MainServiceClient.Callback {
override fun onStopped() {
settingsViewModel.updateStatus("", false)
}
override fun onStarted() {
settingsViewModel.updateStatus("MPD Service Started", true)
}
override fun onError(error: String) {
settingsViewModel.removeClient()
settingsViewModel.updateStatus(error, false)
connectClient()
}
})
settingsViewModel.setClient(client)
}
override fun onStart() {
//mFirstRun = false
connectClient()
super.onStart()
}
override fun onStop() {
settingsViewModel.removeClient()
super.onStop()
}
}

@ -0,0 +1,157 @@
package org.musicpd;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
/*
* Client that bind the Main Service in order to send commands and receive callback
*/
public class MainServiceClient {
private static final String REMOTE_ERROR = "MPD process was killed";
public interface Callback {
public void onStarted();
public void onStopped();
public void onError(String error);
}
private boolean mBound = false;
private final Context mContext;
private Callback mCallback;
private IMain mIMain = null;
private final IMainCallback.Stub mICallback = new IMainCallback.Stub() {
@Override
public void onStopped() throws RemoteException {
mCallback.onStopped();
}
@Override
public void onStarted() throws RemoteException {
mCallback.onStarted();
}
@Override
public void onError(String error) throws RemoteException {
mCallback.onError(error);
}
};
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (this) {
mIMain = IMain.Stub.asInterface(service);
try {
if (mCallback != null)
mIMain.registerCallback(mICallback);
} catch (RemoteException e) {
if (mCallback != null)
mCallback.onError(REMOTE_ERROR);
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (mCallback != null)
mCallback.onError(REMOTE_ERROR);
}
};
public MainServiceClient(Context context, Callback cb) throws IllegalArgumentException {
if (context == null)
throw new IllegalArgumentException("Context can't be null");
mContext = context;
mCallback = cb;
mBound = mContext.bindService(new Intent(mContext, Main.class), mServiceConnection, Context.BIND_AUTO_CREATE);
}
public boolean start() {
synchronized (this) {
if (mIMain != null) {
try {
mIMain.start();
return true;
} catch (RemoteException e) {
}
}
return false;
}
}
public boolean stop() {
synchronized (this) {
if (mIMain != null) {
try {
mIMain.stop();
return true;
} catch (RemoteException e) {
}
}
return false;
}
}
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) {
try {
mIMain.setWakelockEnabled(enabled);
return true;
} catch (RemoteException e) {
}
}
return false;
}
}
public boolean isRunning() {
synchronized (this) {
if (mIMain != null) {
try {
return mIMain.isRunning();
} catch (RemoteException e) {
}
}
return false;
}
}
public void release() {
if (mBound) {
synchronized (this) {
if (mIMain != null && mICallback != null) {
try {
if (mCallback != null)
mIMain.unregisterCallback(mICallback);
} catch (RemoteException e) {
}
}
}
mBound = false;
mContext.unbindService(mServiceConnection);
}
}
}

@ -0,0 +1,34 @@
package org.musicpd;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import androidx.annotation.Nullable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.List;
public class NetworkUtil {
@Nullable
public static String getDeviceIPV4Address(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
LinkProperties linkProperties = connectivityManager.getLinkProperties(connectivityManager.getActiveNetwork());
if (linkProperties != null) {
List<LinkAddress> linkAddresses = linkProperties.getLinkAddresses();
for (LinkAddress address : linkAddresses) {
if (!address.getAddress().isLinkLocalAddress() && !address.getAddress().isLoopbackAddress()) {
InetAddress address1 = address.getAddress();
if (address1 instanceof Inet4Address) {
return address1.getHostAddress();
}
}
}
}
return null;
}
}

@ -0,0 +1,34 @@
package org.musicpd;
import static android.content.Context.MODE_PRIVATE;
import android.content.Context;
import android.content.SharedPreferences;
public class Preferences {
private static final String TAG = "Settings";
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);
}
public static void putBoolean(Context context, String key, boolean value) {
final SharedPreferences prefs = get(context);
if (prefs == null)
return;
final SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(key, value);
editor.apply();
}
public static boolean getBoolean(Context context, String key, boolean defValue) {
final SharedPreferences prefs = get(context);
return prefs != null ? prefs.getBoolean(key, defValue) : defValue;
}
}

@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
package org.musicpd;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import java.util.Set;
public class Receiver extends BroadcastReceiver {
private static final Set<String> BOOT_ACTIONS = Set.of(
"android.intent.action.BOOT_COMPLETED",
"android.intent.action.QUICKBOOT_POWERON"
);
@Override
public void onReceive(Context context, Intent intent) {
Log.d("Receiver", "onReceive: " + intent);
if (BOOT_ACTIONS.contains(intent.getAction())) {
if (Preferences.getBoolean(context,
Preferences.KEY_RUN_ON_BOOT,
false)) {
final boolean wakelock =
Preferences.getBoolean(context,
Preferences.KEY_WAKELOCK, false);
Main.startService(context, wakelock);
}
}
}
}

@ -0,0 +1,34 @@
package org.musicpd.data
import android.util.Log
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
import javax.inject.Singleton
private const val MAX_LOGS = 500
@Singleton
class LoggingRepository @Inject constructor() {
private val _logItemFLow = MutableStateFlow(listOf<String>())
val logItemFLow: StateFlow<List<String>> = _logItemFLow
fun addLogItem(priority: Int, message: String) {
if (_logItemFLow.value.size > MAX_LOGS) {
_logItemFLow.value = _logItemFLow.value.drop(1)
}
val priorityString: String = when (priority) {
Log.DEBUG -> "D"
Log.ERROR -> "E"
Log.INFO -> "I"
Log.VERBOSE -> "V"
Log.WARN -> "W"
else -> ""
}
_logItemFLow.value = _logItemFLow.value + ("$priorityString/$message")
}
}

@ -0,0 +1,79 @@
package org.musicpd.ui
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.VerticalAlignBottom
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Composable
fun LogView(messages: List<String>) {
val lazyListState = rememberLazyListState()
var userScrolled = remember { mutableStateOf(false) }
LaunchedEffect(lazyListState) {
snapshotFlow { lazyListState.isScrollInProgress }
.collect {
if (it) {
userScrolled.value = true
}
}
}
Box(Modifier.fillMaxSize()) {
LazyColumn(
Modifier.padding(4.dp),
lazyListState
) {
items(messages) { message ->
Text(text = message, fontFamily = FontFamily.Monospace)
}
CoroutineScope(Dispatchers.Main).launch {
lazyListState.scrollToItem(messages.count(), 0)
}
}
if (lazyListState.canScrollForward) {
FloatingActionButton(
onClick = {
userScrolled.value = false
CoroutineScope(Dispatchers.Main).launch {
lazyListState.scrollToItem(messages.count(), 0)
}
},
modifier = Modifier.padding(16.dp).align(Alignment.BottomEnd)
) {
Icon(Icons.Filled.VerticalAlignBottom, "Scroll to bottom icon")
}
}
}
}
@Preview
@Composable
fun LogViewPreview() {
val data = listOf("test",
"test2",
"test3")
LogView(data)
}

@ -0,0 +1,109 @@
package org.musicpd.ui
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
enum class Screen {
HOME,
LOGS,
SETTINGS,
}
sealed class NavigationItem(val route: String, val label: String, val icon: ImageVector) {
data object Home : NavigationItem(
Screen.HOME.name,
"Home",
Icons.Default.Home
)
data object Logs : NavigationItem(
Screen.LOGS.name,
"Logs",
Icons.AutoMirrored.Filled.List)
data object Settings : NavigationItem(
Screen.SETTINGS.name,
"Settings",
Icons.Default.Settings)
}
@Composable
fun MPDApp(
navController: NavHostController = rememberNavController(),
settingsViewModel: SettingsViewModel = viewModel()
) {
Scaffold(
topBar = {
},
bottomBar = {
BottomNavigationBar(navController)
},
) { innerPadding ->
NavHost(
navController = navController,
startDestination = NavigationItem.Home.route,
modifier = Modifier.padding(innerPadding)
) {
composable(NavigationItem.Home.route) {
StatusScreen(settingsViewModel)
}
composable(NavigationItem.Logs.route) {
LogView(settingsViewModel.getLogs().collectAsStateWithLifecycle().value)
}
composable(NavigationItem.Settings.route) {
MPDSettings(settingsViewModel)
}
}
}
}
@Composable
fun BottomNavigationBar(navController: NavController) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
val items = listOf(
NavigationItem.Home,
NavigationItem.Logs,
NavigationItem.Settings,
)
NavigationBar {
items.forEach { item ->
NavigationBarItem(
icon = {
Icon(
imageVector = item.icon,
contentDescription = null
)
},
label = { Text (item.label) },
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.startDestinationId)
launchSingleTop = true
}
},
selected = currentRoute == item.route,
)
}
}
}

@ -0,0 +1,39 @@
package org.musicpd.ui
import android.app.Application
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Wifi
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import org.musicpd.NetworkUtil
@Composable
fun NetworkAddress() {
val address = NetworkUtil.getDeviceIPV4Address(LocalContext.current)
val padding = 4.dp
Row(
Modifier
.padding(padding)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Icon(
imageVector = Icons.Default.Wifi,
contentDescription = "Wifi")
Spacer(Modifier.size(padding))
Text(text = address ?: "")
}
}

@ -0,0 +1,77 @@
package org.musicpd.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BatteryAlert
import androidx.compose.material.icons.filled.Headphones
import androidx.compose.material.icons.filled.PowerSettingsNew
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.alorma.compose.settings.storage.preferences.rememberPreferenceBooleanSettingState
import com.alorma.compose.settings.ui.SettingsSwitch
import org.musicpd.Preferences
import org.musicpd.R
@Composable
fun MPDSettings(settingsViewModel: SettingsViewModel) {
val context = LocalContext.current
Column(Modifier.fillMaxSize()) {
SettingsOptions(
onBootChanged = { newValue ->
if (newValue) {
settingsViewModel.startMPD(context)
}
},
onWakeLockChanged = { newValue ->
settingsViewModel.setWakelockEnabled(newValue)
},
onHeadphonesChanged = { newValue ->
settingsViewModel.setPauseOnHeadphonesDisconnect(newValue)
}
)
}
}
@Composable
fun SettingsOptions(
onBootChanged: (Boolean) -> Unit,
onWakeLockChanged: (Boolean) -> Unit,
onHeadphonesChanged: (Boolean) -> Unit
) {
val bootState = rememberPreferenceBooleanSettingState(
key = Preferences.KEY_RUN_ON_BOOT,
defaultValue = false
)
val wakelockState =
rememberPreferenceBooleanSettingState(key = Preferences.KEY_WAKELOCK, defaultValue = false)
val headphoneState = rememberPreferenceBooleanSettingState(
key = Preferences.KEY_PAUSE_ON_HEADPHONES_DISCONNECT,
defaultValue = false
)
SettingsSwitch(
icon = { Icon(imageVector = Icons.Default.PowerSettingsNew, contentDescription = "Power") },
title = { Text(text = stringResource(R.string.checkbox_run_on_boot)) },
onCheckedChange = onBootChanged,
state = bootState
)
SettingsSwitch(
icon = { Icon(imageVector = Icons.Default.BatteryAlert, contentDescription = "Battery") },
title = { Text(text = stringResource(R.string.checkbox_wakelock)) },
onCheckedChange = onWakeLockChanged,
state = wakelockState
)
SettingsSwitch(
icon = { Icon(imageVector = Icons.Default.Headphones, contentDescription = "Headphones") },
title = { Text(text = stringResource(R.string.checkbox_pause_on_headphones_disconnect)) },
onCheckedChange = onHeadphonesChanged,
state = headphoneState
)
}

@ -0,0 +1,73 @@
package org.musicpd.ui
import android.content.Context
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import org.musicpd.Loader
import org.musicpd.MainServiceClient
import org.musicpd.Preferences
import org.musicpd.data.LoggingRepository
import javax.inject.Inject
@HiltViewModel
class SettingsViewModel @Inject constructor(
private var loggingRepository: LoggingRepository
) : ViewModel() {
private var mClient: MainServiceClient? = null
val mpdLoader = Loader
data class StatusUiState(
val statusMessage: String = "",
val running: Boolean = false
)
private val _statusUIState = MutableStateFlow(StatusUiState())
val statusUIState: StateFlow<StatusUiState> = _statusUIState.asStateFlow()
fun getLogs(): StateFlow<List<String>> {
return loggingRepository.logItemFLow
}
fun updateStatus(message: String, running: Boolean) {
_statusUIState.value = StatusUiState(message, running)
}
fun setClient(client: MainServiceClient) {
mClient = client
}
fun removeClient() {
mClient?.release()
mClient = null
}
fun startMPD(context: Context) {
mClient?.start()
if (Preferences.getBoolean(
context,
Preferences.KEY_WAKELOCK, false
)
) mClient?.setWakelockEnabled(true)
if (Preferences.getBoolean(
context,
Preferences.KEY_PAUSE_ON_HEADPHONES_DISCONNECT, false
)
) mClient?.setPauseOnHeadphonesDisconnect(true)
}
fun stopMPD() {
mClient?.stop()
}
fun setWakelockEnabled(enabled: Boolean) {
mClient?.setWakelockEnabled(enabled)
}
fun setPauseOnHeadphonesDisconnect(enabled: Boolean) {
mClient?.setPauseOnHeadphonesDisconnect(enabled)
}
}

@ -0,0 +1,188 @@
package org.musicpd.ui
import android.Manifest
import android.content.Context
import android.os.Build
import android.util.TypedValue
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Circle
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.permissions.shouldShowRationale
import org.musicpd.R
import org.musicpd.utils.openAppSettings
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun StatusScreen(settingsViewModel: SettingsViewModel) {
val storagePermissionState = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
rememberPermissionState(
Manifest.permission.READ_MEDIA_AUDIO
)
} else {
rememberPermissionState(
Manifest.permission.READ_EXTERNAL_STORAGE
)
}
Column(
Modifier
.padding(4.dp)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
NetworkAddress()
ServerStatus(settingsViewModel, storagePermissionState)
AudioMediaPermission(storagePermissionState)
MPDLoaderStatus(settingsViewModel)
}
}
@ColorInt
fun getThemeColorAttribute(context: Context, @AttrRes attr: Int): Int {
val value = TypedValue()
if (context.theme.resolveAttribute(attr, value, true)) {
return value.data
}
return android.graphics.Color.BLACK
}
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun ServerStatus(settingsViewModel: SettingsViewModel, storagePermissionState: PermissionState) {
val context = LocalContext.current
val statusUiState by settingsViewModel.statusUIState.collectAsState()
Column {
Row(
Modifier
.padding(4.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
imageVector = Icons.Default.Circle,
contentDescription = "",
tint = Color(
getThemeColorAttribute(
context,
if (statusUiState.running) R.attr.appColorPositive else R.attr.appColorNegative
)
),
modifier = Modifier
.padding(end = 8.dp)
.alpha(0.6f)
)
Text(text = stringResource(id = if (statusUiState.running) R.string.running else R.string.stopped))
}
Button(
onClick = {
if (statusUiState.running)
settingsViewModel.stopMPD()
else
settingsViewModel.startMPD(context)
},
enabled = settingsViewModel.mpdLoader.isLoaded
&& storagePermissionState.status.isGranted
) {
Text(
text = stringResource(id = if (statusUiState.running) R.string.stopMPD else R.string.startMPD)
)
}
}
Row(
Modifier
.padding(4.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly
) {
Text(text = statusUiState.statusMessage)
}
}
}
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun AudioMediaPermission(storagePermissionState: PermissionState) {
val permissionStatus = storagePermissionState.status
if (!permissionStatus.isGranted) {
val context = LocalContext.current
Column(
Modifier
.padding(4.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
stringResource(id = R.string.external_files_permission_request),
Modifier.padding(16.dp)
)
if (storagePermissionState.status.shouldShowRationale) {
Button(onClick = {
storagePermissionState.launchPermissionRequest()
}) {
Text("Request permission")
}
} else {
OutlinedButton(
onClick = {
openAppSettings(context, context.packageName)
},
Modifier.padding(16.dp)
) {
Text(
stringResource(id = R.string.title_open_app_info),
color = MaterialTheme.colorScheme.secondary
)
}
}
}
}
}
@Composable
fun MPDLoaderStatus(settingsViewModel: SettingsViewModel) {
val loader = settingsViewModel.mpdLoader
if (!loader.isLoaded) {
val context = LocalContext.current
SelectionContainer {
Text(
loader.loadFailureMessage(context),
Modifier.padding(16.dp),
color = MaterialTheme.colorScheme.error
)
}
}
}

@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
package org.musicpd.utils
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import android.util.Log
private const val TAG = "IntentUtils"
fun openAppSettings(
context: Context,
packageName: String
) {
try {
context.startActivity(Intent().apply {
setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
setData(Uri.parse("package:$packageName"))
addCategory(Intent.CATEGORY_DEFAULT)
addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
})
} catch (e: ActivityNotFoundException) {
Log.e(
TAG,
"failed to open app settings for package: $packageName", e
)
}
}

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z"/>
</vector>

@ -0,0 +1,239 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="320dp"
android:height="180dp"
android:viewportWidth="320"
android:viewportHeight="180">
<path
android:pathData="M179.13,108.5H162.71V106.64C163.3,106.62 164.06,106.56 164.99,106.46C165.93,106.35 166.58,106.2 166.93,106.01C167.47,105.68 167.86,105.31 168.1,104.89C168.37,104.45 168.5,103.91 168.5,103.26V76.24H168.1L155.43,107.9H154.12L142.05,75.58H141.71V97.76C141.71,99.91 141.84,101.54 142.1,102.66C142.38,103.78 142.8,104.58 143.36,105.07C143.74,105.44 144.54,105.79 145.74,106.12C146.94,106.45 147.73,106.62 148.1,106.64V108.5H133.09V106.64C133.88,106.57 134.7,106.44 135.55,106.25C136.43,106.06 137.1,105.77 137.57,105.38C138.18,104.89 138.6,104.14 138.83,103.13C139.05,102.12 139.17,100.43 139.17,98.05V79.04C139.17,77.94 139.04,77.04 138.77,76.34C138.51,75.64 138.14,75.07 137.65,74.64C137.11,74.17 136.44,73.82 135.66,73.59C134.87,73.36 134.09,73.23 133.33,73.2V71.34H146L156.63,99.2L165.72,75.9C166.05,75.04 166.33,74.15 166.56,73.22C166.8,72.28 166.93,71.65 166.95,71.34H179.08V73.2C178.59,73.22 177.96,73.29 177.19,73.43C176.44,73.57 175.89,73.7 175.54,73.83C174.95,74.04 174.55,74.39 174.34,74.87C174.13,75.36 174.02,75.9 174.02,76.47V103.26C174.02,103.87 174.13,104.39 174.34,104.81C174.55,105.23 174.95,105.59 175.54,105.91C175.86,106.08 176.41,106.25 177.22,106.4C178.02,106.54 178.66,106.62 179.13,106.64V108.5Z"
android:fillColor="#000000"/>
<path
android:pathData="M212.6,80.5C212.6,82.44 212.21,84.16 211.45,85.66C210.7,87.15 209.65,88.38 208.3,89.36C206.98,90.33 205.52,91.05 203.93,91.5C202.34,91.96 200.66,92.18 198.88,92.18H194.71V103.45C194.71,104.06 194.81,104.6 195,105.07C195.21,105.52 195.63,105.87 196.26,106.12C196.57,106.24 197.12,106.35 197.91,106.46C198.71,106.56 199.44,106.62 200.11,106.64V108.5H184.16V106.64C184.58,106.61 185.18,106.54 185.96,106.46C186.77,106.37 187.33,106.26 187.64,106.12C188.16,105.89 188.54,105.56 188.77,105.12C189.01,104.68 189.13,104.13 189.13,103.45V76.63C189.13,76.02 189.05,75.47 188.87,74.98C188.7,74.49 188.29,74.12 187.64,73.88C186.98,73.65 186.31,73.49 185.65,73.41C185.01,73.3 184.45,73.23 183.98,73.2V71.34H200.95C204.4,71.34 207.2,72.18 209.35,73.85C211.52,75.51 212.6,77.73 212.6,80.5ZM204.64,86.84C205.23,86 205.62,85.14 205.82,84.25C206.01,83.34 206.1,82.53 206.1,81.81C206.1,80.82 205.98,79.81 205.74,78.78C205.51,77.75 205.11,76.85 204.53,76.08C203.92,75.26 203.12,74.62 202.12,74.17C201.13,73.71 199.89,73.49 198.4,73.49H194.71V89.91H197.38C199.27,89.91 200.8,89.62 201.97,89.04C203.15,88.45 204.04,87.71 204.64,86.84Z"
android:fillColor="#000000"/>
<path
android:pathData="M252.48,90.14C252.48,93.3 251.89,96.04 250.7,98.36C249.52,100.69 247.97,102.59 246.07,104.07C244.15,105.56 241.99,106.67 239.6,107.4C237.21,108.13 234.74,108.5 232.19,108.5H216.79V106.64C217.29,106.64 217.95,106.6 218.75,106.51C219.57,106.4 220.12,106.29 220.38,106.17C220.9,105.94 221.28,105.61 221.5,105.17C221.75,104.72 221.87,104.18 221.87,103.55V76.73C221.87,76.14 221.76,75.61 221.55,75.14C221.36,74.66 220.97,74.29 220.38,74.01C219.84,73.75 219.25,73.56 218.62,73.43C217.99,73.31 217.45,73.23 217,73.2V71.34H233.24C235.47,71.34 237.67,71.69 239.84,72.39C242,73.07 243.89,73.99 245.49,75.16C247.67,76.72 249.38,78.75 250.63,81.26C251.86,83.78 252.48,86.74 252.48,90.14ZM246.07,90.12C246.07,87.62 245.74,85.37 245.07,83.36C244.41,81.33 243.44,79.57 242.17,78.07C240.96,76.64 239.48,75.51 237.71,74.69C235.97,73.87 234.02,73.46 231.87,73.46C231.16,73.46 230.35,73.48 229.44,73.51C228.55,73.53 227.88,73.55 227.45,73.56V102.14C227.45,103.72 227.91,104.82 228.84,105.44C229.76,106.05 231.18,106.35 233.1,106.35C235.32,106.35 237.26,105.96 238.92,105.17C240.58,104.39 241.92,103.3 242.95,101.9C244.03,100.43 244.82,98.74 245.31,96.82C245.82,94.88 246.07,92.65 246.07,90.12Z"
android:fillColor="#000000"/>
<group>
<clip-path
android:pathData="M23,51h71v71h-71z"/>
<path
android:pathData="M87.49,88.31C87.49,88.07 87.29,87.87 87.06,87.87H60.89C60.66,87.87 60.46,88.07 60.46,88.31V110.83C60.46,111.07 60.66,111.26 60.89,111.26H87.06C87.29,111.26 87.49,111.07 87.49,110.83V88.31Z"
android:fillColor="#000000"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M93.82,68.38C93.82,68.14 93.63,67.95 93.39,67.95H59.19C58.96,67.95 58.76,68.14 58.76,68.38V97.86C58.76,98.1 58.96,98.29 59.19,98.29H93.39C93.63,98.29 93.82,98.1 93.82,97.86V68.38Z"
android:fillColor="#000000"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M91.36,96.94C91.36,96.73 91.2,96.57 90.99,96.57H59.64C59.44,96.57 59.28,96.73 59.28,96.94V101.2C59.28,101.4 59.44,101.56 59.64,101.56H90.99C91.2,101.56 91.36,101.4 91.36,101.2V96.94Z"
android:fillColor="#000000"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M89.3,96.89C89.3,96.75 89.19,96.64 89.05,96.64H59.09C58.96,96.64 58.85,96.75 58.85,96.89V99.8C58.85,99.94 58.96,100.05 59.09,100.05H89.05C89.19,100.05 89.3,99.94 89.3,99.8V96.89Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="76.53"
android:startY="102.12"
android:endX="69.28"
android:endY="95.45"
android:type="linear">
<item android:offset="0" android:color="#BFD2D2D2"/>
<item android:offset="1" android:color="#BFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M58.61,96.89C58.61,96.63 58.83,96.41 59.09,96.41H89.05C89.32,96.41 89.53,96.63 89.53,96.89V99.8C89.53,100.07 89.32,100.28 89.05,100.28H59.09C58.83,100.28 58.61,100.07 58.61,99.8V96.89ZM59.09,96.87C59.08,96.87 59.08,96.88 59.08,96.89V99.8C59.08,99.81 59.08,99.82 59.09,99.82H89.05C89.06,99.82 89.07,99.81 89.07,99.8V96.89C89.07,96.88 89.06,96.87 89.05,96.87H59.09Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M90.5,69.91C90.5,69.41 90.09,69 89.59,69H59.29C58.79,69 58.38,69.41 58.38,69.91V94.21C58.38,94.71 58.79,95.12 59.29,95.12H89.59C90.09,95.12 90.5,94.71 90.5,94.21V69.91Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="91.12"
android:startY="94.89"
android:endX="74.39"
android:endY="79.87"
android:type="linear">
<item android:offset="0" android:color="#FFD2D2D2"/>
<item android:offset="1" android:color="#FFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M85.59,110.3C85.59,110.1 85.42,109.93 85.22,109.93H61.22C61.02,109.93 60.86,110.1 60.86,110.3V113.42C60.86,113.62 61.02,113.78 61.22,113.78H85.22C85.42,113.78 85.59,113.62 85.59,113.42V110.3Z"
android:fillColor="#000000"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M92.05,67.72C92.05,67.29 91.71,66.94 91.28,66.94H56.97C56.55,66.94 56.2,67.29 56.2,67.72V96.16C56.2,96.59 56.55,96.93 56.97,96.93H91.28C91.71,96.93 92.05,96.59 92.05,96.16V67.72Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="95.17"
android:startY="93.03"
android:endX="87.12"
android:endY="79.61"
android:type="linear">
<item android:offset="0" android:color="#FFD2D2D2"/>
<item android:offset="1" android:color="#FFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M55.74,67.72C55.74,67.04 56.29,66.48 56.97,66.48H91.28C91.96,66.48 92.51,67.04 92.51,67.72V96.16C92.51,96.84 91.96,97.39 91.28,97.39H56.97C56.29,97.39 55.74,96.84 55.74,96.16V67.72ZM56.97,67.4C56.8,67.4 56.66,67.54 56.66,67.72V96.16C56.66,96.33 56.8,96.47 56.97,96.47H91.28C91.45,96.47 91.59,96.33 91.59,96.16V67.72C91.59,67.54 91.45,67.4 91.28,67.4H56.97Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M88.17,70.66C88.17,70.49 88.03,70.36 87.87,70.36H60.11C59.94,70.36 59.81,70.49 59.81,70.66V92.22C59.81,92.39 59.94,92.52 60.11,92.52H87.87C88.03,92.52 88.17,92.39 88.17,92.22V70.66Z"
android:fillColor="#00B4ED"
android:fillType="evenOdd"/>
<path
android:pathData="M59.59,70.66C59.59,70.37 59.82,70.14 60.11,70.14H87.87C88.16,70.14 88.39,70.37 88.39,70.66V92.22C88.39,92.51 88.16,92.74 87.87,92.74H60.11C59.82,92.74 59.59,92.51 59.59,92.22V70.66ZM60.11,70.58C60.06,70.58 60.03,70.61 60.03,70.66V92.22C60.03,92.27 60.06,92.31 60.11,92.31H87.87C87.91,92.31 87.95,92.27 87.95,92.22V70.66C87.95,70.61 87.91,70.58 87.87,70.58H60.11Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M84.93,89.59C84.93,89.09 84.52,88.68 84.02,88.68H61.07C60.57,88.68 60.17,89.09 60.17,89.59V107.91C60.17,108.41 60.57,108.82 61.07,108.82H84.02C84.52,108.82 84.93,108.41 84.93,107.91V89.59Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="85.4"
android:startY="108.64"
android:endX="72.51"
android:endY="97.06"
android:type="linear">
<item android:offset="0" android:color="#FFD2D2D2"/>
<item android:offset="1" android:color="#FFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M72.64,108.86C72.35,110.81 63.69,112.41 53.46,112.41C43.24,112.41 35.07,110.81 35.36,108.86C35.66,106.92 44.32,105.32 54.54,105.32C64.77,105.32 72.94,106.92 72.64,108.86Z"
android:fillColor="#444040"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M46.49,87.74C43.2,95.65 45.43,104.45 51.42,107.24C57.42,110.04 65.06,105.82 68.34,97.92C71.63,90.01 69.4,81.21 63.41,78.42C57.41,75.62 49.77,79.83 46.49,87.74Z"
android:fillColor="#4E4D4B"
android:fillType="evenOdd"/>
<path
android:pathData="M68.58,86.44C69.43,89.79 69.19,93.78 67.61,97.58C66.03,101.38 63.41,104.26 60.51,105.86C57.6,107.47 54.45,107.76 51.73,106.49C49.01,105.23 47.09,102.57 46.25,99.22C45.4,95.87 45.64,91.88 47.22,88.08C48.8,84.28 51.42,81.4 54.32,79.79C57.23,78.19 60.37,77.9 63.1,79.17C65.82,80.43 67.74,83.09 68.58,86.44ZM70.13,86.06C69.18,82.34 66.99,79.19 63.72,77.67C60.44,76.14 56.77,76.56 53.54,78.34C50.31,80.12 47.46,83.29 45.75,87.4C44.04,91.5 43.76,95.87 44.7,99.6C45.65,103.32 47.84,106.47 51.11,107.99C54.39,109.52 58.06,109.1 61.29,107.32C64.52,105.54 67.37,102.37 69.08,98.26C70.78,94.15 71.07,89.79 70.13,86.06Z"
android:fillColor="#000000"
android:fillAlpha="0.95"
android:fillType="evenOdd"/>
<path
android:pathData="M30.48,75.66C23.76,88.96 25.17,103.77 33.61,108.47C42.05,113.17 54.53,106.08 61.25,92.78C67.98,79.48 66.56,64.67 58.12,59.98C49.68,55.28 37.21,62.36 30.48,75.66Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="89.23"
android:startY="61.39"
android:endX="8.66"
android:endY="47.26"
android:type="linear">
<item android:offset="0" android:color="#FFFFFFFF"/>
<item android:offset="1" android:color="#FF000000"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M64.24,73.24C64.78,78.94 63.51,85.74 60.24,92.22C56.96,98.7 52.31,103.62 47.51,106.34C42.69,109.07 37.89,109.53 34.13,107.43C30.37,105.34 28.04,100.92 27.49,95.2C26.95,89.5 28.22,82.7 31.49,76.22C34.77,69.75 39.42,64.83 44.22,62.1C49.04,59.37 53.84,58.92 57.6,61.01C61.36,63.1 63.7,67.53 64.24,73.24ZM66.51,73.07C65.92,66.88 63.33,61.55 58.65,58.95C53.96,56.34 48.31,57.08 43.09,60.04C37.86,63 32.92,68.28 29.47,75.1C26.02,81.92 24.63,89.17 25.23,95.38C25.81,101.57 28.4,106.9 33.09,109.5C37.77,112.11 43.42,111.37 48.64,108.41C53.87,105.44 58.81,100.17 62.26,93.35C65.71,86.52 67.1,79.27 66.51,73.07Z"
android:fillColor="#000000"
android:fillAlpha="0.95"
android:fillType="evenOdd"/>
<path
android:pathData="M31.01,75.59C25.32,87.25 26.23,100.23 33.04,104.34C39.84,108.46 50.12,102.25 55.81,90.6C61.51,78.94 60.59,65.96 53.78,61.84C46.98,57.73 36.7,63.93 31.01,75.59Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="16.83"
android:centerY="104.4"
android:gradientRadius="32.44"
android:type="radial">
<item android:offset="0" android:color="#9EFFFFFF"/>
<item android:offset="1" android:color="#FF5D6567"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M59.34,73.4C59.71,78.58 58.52,84.71 55.68,90.52C52.85,96.33 48.87,100.77 44.77,103.25C40.66,105.73 36.44,106.23 33.1,104.21C29.76,102.19 27.85,97.98 27.48,92.79C27.12,87.61 28.3,81.48 31.14,75.67C33.97,69.86 37.95,65.42 42.05,62.94C46.16,60.46 50.38,59.96 53.72,61.98C57.06,64 58.97,68.21 59.34,73.4ZM59.63,73.39C59.26,68.14 57.32,63.8 53.85,61.71C50.39,59.61 46.06,60.15 41.9,62.66C37.74,65.17 33.73,69.66 30.88,75.51C28.02,81.36 26.82,87.55 27.19,92.8C27.56,98.04 29.5,102.38 32.97,104.48C36.43,106.58 40.76,106.03 44.92,103.52C49.08,101.01 53.09,96.53 55.94,90.68C58.8,84.83 60,78.64 59.63,73.39Z"
android:fillColor="#000000"
android:fillAlpha="0.98"
android:fillType="evenOdd"/>
<path
android:pathData="M42.76,79.77C39.61,85.38 38.93,92.2 41.26,94.88C43.59,97.55 48.1,95.14 51.24,89.54C54.39,83.93 55.06,77.11 52.74,74.43C50.41,71.75 45.9,74.16 42.76,79.77Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M42.46,79.6C39.52,84.65 38.89,90.8 41.07,93.21C43.24,95.62 47.46,93.45 50.4,88.4C53.35,83.35 53.98,77.21 51.8,74.79C49.62,72.38 45.41,74.55 42.46,79.6Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="34.56"
android:startY="87.9"
android:endX="59.05"
android:endY="97.29"
android:type="linear">
<item android:offset="0" android:color="#FFD7D5D5"/>
<item android:offset="1" android:color="#66000000"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M52.89,80.57C52.64,83.01 51.76,85.78 50.3,88.28C48.84,90.79 47.06,92.58 45.39,93.44C43.72,94.3 42.18,94.22 41.15,93.07C40.11,91.93 39.72,89.87 39.97,87.43C40.22,85 41.11,82.22 42.57,79.72C44.03,77.21 45.8,75.43 47.47,74.57C49.15,73.7 50.69,73.78 51.72,74.93C52.75,76.07 53.14,78.13 52.89,80.57ZM53.15,80.64C53.41,78.15 53.02,75.93 51.88,74.66C50.73,73.39 49.08,73.35 47.37,74.23C45.65,75.11 43.84,76.94 42.36,79.48C40.88,82.03 39.97,84.85 39.71,87.36C39.46,89.85 39.84,92.08 40.99,93.35C42.13,94.61 43.79,94.65 45.5,93.77C47.22,92.89 49.02,91.06 50.51,88.52C51.99,85.97 52.9,83.15 53.15,80.64Z"
android:fillColor="#3F3B3B"
android:fillType="evenOdd"/>
<path
android:pathData="M84,110.24C84,110.1 83.89,109.99 83.75,109.99H60.77C60.64,109.99 60.53,110.1 60.53,110.24V112.37C60.53,112.5 60.64,112.61 60.77,112.61H83.75C83.89,112.61 84,112.5 84,112.37V110.24Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="74.16"
android:startY="114.32"
android:endX="68.55"
android:endY="108.99"
android:type="linear">
<item android:offset="0" android:color="#BFD2D2D2"/>
<item android:offset="1" android:color="#BFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M60.3,110.24C60.3,109.97 60.51,109.76 60.77,109.76H83.75C84.02,109.76 84.23,109.97 84.23,110.24V112.37C84.23,112.63 84.02,112.85 83.75,112.85H60.77C60.51,112.85 60.3,112.63 60.3,112.37V110.24ZM60.77,110.22C60.76,110.22 60.76,110.23 60.76,110.24V112.37C60.76,112.38 60.76,112.39 60.77,112.39H83.75C83.76,112.39 83.77,112.38 83.77,112.37V110.24C83.77,110.23 83.76,110.22 83.75,110.22H60.77Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M86.12,87.87C86.12,87.44 85.78,87.1 85.35,87.1H59.26C58.83,87.1 58.49,87.44 58.49,87.87V109.44C58.49,109.87 58.83,110.21 59.26,110.21H85.35C85.78,110.21 86.12,109.87 86.12,109.44V87.87Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="88.53"
android:startY="107.21"
android:endX="82.32"
android:endY="96.86"
android:type="linear">
<item android:offset="0" android:color="#FFD2D2D2"/>
<item android:offset="1" android:color="#FFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M58.13,87.87C58.13,87.25 58.64,86.74 59.26,86.74H85.35C85.97,86.74 86.48,87.25 86.48,87.87V109.44C86.48,110.06 85.97,110.57 85.35,110.57H59.26C58.64,110.57 58.13,110.06 58.13,109.44V87.87ZM59.26,87.45C59.03,87.45 58.84,87.64 58.84,87.87V109.44C58.84,109.67 59.03,109.86 59.26,109.86H85.35C85.58,109.86 85.77,109.67 85.77,109.44V87.87C85.77,87.64 85.58,87.45 85.35,87.45H59.26Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M83.13,90.18C83.13,90.02 82.99,89.88 82.83,89.88H61.57C61.4,89.88 61.27,90.02 61.27,90.18V106.67C61.27,106.83 61.4,106.97 61.57,106.97H82.83C82.99,106.97 83.13,106.83 83.13,106.67V90.18Z"
android:fillColor="#003D88"
android:fillType="evenOdd"/>
<path
android:pathData="M61.1,90.18C61.1,89.92 61.31,89.71 61.57,89.71H82.83C83.09,89.71 83.3,89.92 83.3,90.18V106.67C83.3,106.93 83.09,107.14 82.83,107.14H61.57C61.31,107.14 61.1,106.93 61.1,106.67V90.18ZM61.57,90.05C61.5,90.05 61.44,90.11 61.44,90.18V106.67C61.44,106.74 61.5,106.8 61.57,106.8H82.83C82.9,106.8 82.96,106.74 82.96,106.67V90.18C82.96,90.11 82.9,90.05 82.83,90.05H61.57Z"
android:fillColor="#000000"
android:fillAlpha="0.93"
android:fillType="evenOdd"/>
</group>
</vector>

@ -0,0 +1,235 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.7121053"
android:scaleY="0.7121053"
android:translateX="14.83421"
android:translateY="16.25842">
<group>
<clip-path
android:pathData="M15,15h78v78h-78z"/>
<path
android:pathData="M85.85,55.98C85.85,55.72 85.63,55.51 85.37,55.51H56.63C56.37,55.51 56.15,55.72 56.15,55.98V80.73C56.15,80.99 56.37,81.2 56.63,81.2H85.37C85.63,81.2 85.85,80.99 85.85,80.73V55.98Z"
android:fillColor="#000000"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M92.81,34.1C92.81,33.83 92.59,33.62 92.33,33.62H54.76C54.5,33.62 54.29,33.83 54.29,34.1V66.48C54.29,66.74 54.5,66.96 54.76,66.96H92.33C92.59,66.96 92.81,66.74 92.81,66.48V34.1Z"
android:fillColor="#000000"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M90.1,65.47C90.1,65.24 89.92,65.06 89.7,65.06H55.26C55.03,65.06 54.85,65.24 54.85,65.47V70.15C54.85,70.37 55.03,70.55 55.26,70.55H89.7C89.92,70.55 90.1,70.37 90.1,70.15V65.47Z"
android:fillColor="#000000"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M87.84,65.41C87.84,65.26 87.72,65.14 87.57,65.14H54.65C54.5,65.14 54.38,65.26 54.38,65.41V68.61C54.38,68.76 54.5,68.89 54.65,68.89H87.57C87.72,68.89 87.84,68.76 87.84,68.61V65.41Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="73.8"
android:startY="71.16"
android:endX="65.84"
android:endY="63.83"
android:type="linear">
<item android:offset="0" android:color="#BFD2D2D2"/>
<item android:offset="1" android:color="#BFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M54.13,65.41C54.13,65.12 54.36,64.89 54.65,64.89H87.57C87.86,64.89 88.09,65.12 88.09,65.41V68.61C88.09,68.9 87.86,69.14 87.57,69.14H54.65C54.36,69.14 54.13,68.9 54.13,68.61V65.41ZM54.65,65.39C54.64,65.39 54.63,65.4 54.63,65.41V68.61C54.63,68.62 54.64,68.63 54.65,68.63H87.57C87.58,68.63 87.59,68.62 87.59,68.61V65.41C87.59,65.4 87.58,65.39 87.57,65.39H54.65Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M89.15,35.77C89.15,35.22 88.71,34.78 88.16,34.78H54.86C54.31,34.78 53.87,35.22 53.87,35.77V62.47C53.87,63.02 54.31,63.47 54.86,63.47H88.16C88.71,63.47 89.15,63.02 89.15,62.47V35.77Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="89.84"
android:startY="63.22"
android:endX="71.46"
android:endY="46.71"
android:type="linear">
<item android:offset="0" android:color="#FFD2D2D2"/>
<item android:offset="1" android:color="#FFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M83.76,80.15C83.76,79.92 83.58,79.74 83.36,79.74H56.99C56.77,79.74 56.59,79.92 56.59,80.15V83.57C56.59,83.79 56.77,83.97 56.99,83.97H83.36C83.58,83.97 83.76,83.79 83.76,83.57V80.15Z"
android:fillColor="#000000"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M90.86,33.37C90.86,32.9 90.48,32.51 90.01,32.51H52.32C51.85,32.51 51.47,32.9 51.47,33.37V64.61C51.47,65.08 51.85,65.46 52.32,65.46H90.01C90.48,65.46 90.86,65.08 90.86,64.61V33.37Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="94.29"
android:startY="61.18"
android:endX="85.44"
android:endY="46.43"
android:type="linear">
<item android:offset="0" android:color="#FFD2D2D2"/>
<item android:offset="1" android:color="#FFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M50.97,33.37C50.97,32.62 51.58,32.01 52.32,32.01H90.01C90.76,32.01 91.37,32.62 91.37,33.37V64.61C91.37,65.36 90.76,65.97 90.01,65.97H52.32C51.58,65.97 50.97,65.36 50.97,64.61V33.37ZM52.32,33.02C52.13,33.02 51.98,33.17 51.98,33.37V64.61C51.98,64.8 52.13,64.96 52.32,64.96H90.01C90.2,64.96 90.36,64.8 90.36,64.61V33.37C90.36,33.17 90.2,33.02 90.01,33.02H52.32Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M86.59,36.59C86.59,36.41 86.45,36.26 86.26,36.26H55.77C55.59,36.26 55.44,36.41 55.44,36.59V60.29C55.44,60.47 55.59,60.62 55.77,60.62H86.26C86.45,60.62 86.59,60.47 86.59,60.29V36.59Z"
android:fillColor="#00B4ED"
android:fillType="evenOdd"/>
<path
android:pathData="M55.2,36.59C55.2,36.28 55.45,36.02 55.77,36.02H86.26C86.58,36.02 86.83,36.28 86.83,36.59V60.29C86.83,60.6 86.58,60.86 86.26,60.86H55.77C55.45,60.86 55.2,60.6 55.2,60.29V36.59ZM55.77,36.51C55.72,36.51 55.68,36.55 55.68,36.59V60.29C55.68,60.34 55.72,60.38 55.77,60.38H86.26C86.31,60.38 86.35,60.34 86.35,60.29V36.59C86.35,36.55 86.31,36.51 86.26,36.51H55.77Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M83.03,57.4C83.03,56.85 82.59,56.4 82.04,56.4H56.83C56.28,56.4 55.83,56.85 55.83,57.4V77.52C55.83,78.07 56.28,78.52 56.83,78.52H82.04C82.59,78.52 83.03,78.07 83.03,77.52V57.4Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="83.56"
android:startY="78.32"
android:endX="69.39"
android:endY="65.6"
android:type="linear">
<item android:offset="0" android:color="#FFD2D2D2"/>
<item android:offset="1" android:color="#FFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M69.54,78.57C69.21,80.71 59.7,82.46 48.47,82.46C37.23,82.46 28.26,80.71 28.58,78.57C28.91,76.43 38.42,74.68 49.65,74.68C60.89,74.68 69.87,76.43 69.54,78.57Z"
android:fillColor="#444040"
android:fillAlpha="0.47"
android:fillType="evenOdd"/>
<path
android:pathData="M40.8,55.36C37.19,64.05 39.64,73.72 46.22,76.79C52.81,79.86 61.2,75.23 64.81,66.55C68.42,57.86 65.98,48.19 59.39,45.12C52.8,42.05 44.41,46.68 40.8,55.36Z"
android:fillColor="#4E4D4B"
android:fillType="evenOdd"/>
<path
android:pathData="M65.08,53.93C66.01,57.61 65.74,62 64.01,66.17C62.27,70.34 59.4,73.51 56.2,75.27C53.01,77.03 49.55,77.36 46.57,75.97C43.58,74.57 41.47,71.66 40.54,67.98C39.61,64.3 39.87,59.91 41.61,55.74C43.34,51.56 46.22,48.39 49.41,46.63C52.6,44.87 56.06,44.55 59.05,45.94C62.04,47.33 64.15,50.25 65.08,53.93ZM66.77,53.52C65.74,49.43 63.33,45.97 59.73,44.3C56.13,42.62 52.1,43.08 48.55,45.03C45,46.99 41.87,50.47 39.99,54.99C38.12,59.5 37.81,64.29 38.84,68.39C39.88,72.48 42.29,75.93 45.88,77.61C49.48,79.29 53.51,78.83 57.06,76.87C60.62,74.92 63.74,71.43 65.62,66.92C67.5,62.41 67.81,57.62 66.77,53.52Z"
android:fillColor="#000000"
android:fillAlpha="0.95"
android:fillType="evenOdd"/>
<path
android:pathData="M23.22,42.09C15.83,56.7 17.38,72.97 26.65,78.13C35.93,83.29 49.63,75.52 57.02,60.9C64.41,46.29 62.86,30.02 53.59,24.86C44.31,19.7 30.61,27.48 23.22,42.09Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="87.76"
android:startY="26.41"
android:endX="-0.75"
android:endY="10.89"
android:type="linear">
<item android:offset="0" android:color="#FFFFFFFF"/>
<item android:offset="1" android:color="#FF000000"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M60.31,39.44C60.9,45.7 59.51,53.17 55.91,60.29C52.31,67.4 47.2,72.81 41.92,75.8C36.63,78.8 31.36,79.3 27.23,77C23.1,74.7 20.53,69.84 19.93,63.56C19.34,57.3 20.73,49.83 24.33,42.71C27.93,35.59 33.04,30.19 38.32,27.2C43.61,24.2 48.88,23.7 53.01,26C57.14,28.3 59.71,33.16 60.31,39.44ZM62.8,39.24C62.15,32.44 59.3,26.59 54.16,23.73C49.02,20.87 42.8,21.68 37.08,24.93C31.33,28.19 25.9,33.98 22.11,41.47C18.32,48.97 16.79,56.94 17.44,63.76C18.09,70.56 20.94,76.41 26.08,79.27C31.22,82.13 37.44,81.32 43.16,78.07C48.91,74.81 54.34,69.02 58.13,61.52C61.92,54.03 63.45,46.06 62.8,39.24Z"
android:fillColor="#000000"
android:fillAlpha="0.95"
android:fillType="evenOdd"/>
<path
android:pathData="M23.8,42.01C17.54,54.82 18.55,69.08 26.03,73.6C33.5,78.12 44.8,71.31 51.05,58.5C57.3,45.69 56.29,31.43 48.82,26.91C41.34,22.39 30.05,29.21 23.8,42.01Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="8.22"
android:centerY="73.66"
android:gradientRadius="35.64"
android:type="radial">
<item android:offset="0" android:color="#9EFFFFFF"/>
<item android:offset="1" android:color="#FF5D6567"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M54.92,39.6C55.32,45.3 54.02,52.03 50.91,58.41C47.79,64.79 43.42,69.68 38.91,72.4C34.4,75.12 29.77,75.67 26.1,73.45C22.43,71.23 20.32,66.61 19.92,60.91C19.52,55.22 20.82,48.48 23.94,42.1C27.05,35.72 31.42,30.84 35.93,28.12C40.45,25.39 45.08,24.84 48.75,27.06C52.41,29.28 54.52,33.91 54.92,39.6ZM55.24,39.6C54.84,33.83 52.7,29.07 48.89,26.76C45.09,24.46 40.33,25.06 35.77,27.81C31.2,30.57 26.79,35.5 23.65,41.93C20.51,48.35 19.2,55.15 19.6,60.92C20.01,66.68 22.14,71.45 25.95,73.75C29.76,76.06 34.51,75.46 39.08,72.7C43.65,69.94 48.05,65.01 51.19,58.59C54.33,52.16 55.65,45.36 55.24,39.6Z"
android:fillColor="#000000"
android:fillAlpha="0.98"
android:fillType="evenOdd"/>
<path
android:pathData="M36.7,46.61C33.25,52.77 32.51,60.26 35.06,63.2C37.62,66.14 42.57,63.5 46.03,57.34C49.48,51.18 50.22,43.69 47.67,40.74C45.11,37.8 40.16,40.45 36.7,46.61Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M36.38,46.42C33.15,51.97 32.46,58.72 34.85,61.37C37.24,64.02 41.87,61.64 45.1,56.09C48.34,50.54 49.03,43.79 46.64,41.14C44.25,38.49 39.62,40.87 36.38,46.42Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="27.7"
android:startY="55.54"
android:endX="54.6"
android:endY="65.85"
android:type="linear">
<item android:offset="0" android:color="#FFD7D5D5"/>
<item android:offset="1" android:color="#66000000"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M47.84,47.49C47.56,50.16 46.59,53.21 44.99,55.96C43.38,58.71 41.44,60.68 39.6,61.62C37.76,62.57 36.07,62.48 34.93,61.22C33.8,59.96 33.37,57.7 33.65,55.02C33.92,52.35 34.89,49.3 36.5,46.55C38.1,43.8 40.05,41.83 41.89,40.89C43.73,39.94 45.42,40.03 46.55,41.29C47.69,42.55 48.11,44.8 47.84,47.49ZM48.12,47.57C48.41,44.82 47.98,42.38 46.73,40.99C45.47,39.6 43.65,39.55 41.77,40.52C39.88,41.49 37.9,43.5 36.27,46.29C34.64,49.09 33.64,52.19 33.36,54.94C33.08,57.69 33.5,60.13 34.76,61.52C36.02,62.91 37.84,62.96 39.72,61.99C41.61,61.02 43.59,59.01 45.22,56.22C46.85,53.42 47.84,50.32 48.12,47.57Z"
android:fillColor="#3F3B3B"
android:fillType="evenOdd"/>
<path
android:pathData="M82.02,80.08C82.02,79.93 81.9,79.8 81.74,79.8H56.5C56.35,79.8 56.23,79.93 56.23,80.08V82.42C56.23,82.57 56.35,82.69 56.5,82.69H81.74C81.9,82.69 82.02,82.57 82.02,82.42V80.08Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="71.21"
android:startY="84.56"
android:endX="65.04"
android:endY="78.7"
android:type="linear">
<item android:offset="0" android:color="#BFD2D2D2"/>
<item android:offset="1" android:color="#BFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M55.97,80.08C55.97,79.79 56.21,79.55 56.5,79.55H81.74C82.04,79.55 82.27,79.79 82.27,80.08V82.42C82.27,82.71 82.04,82.94 81.74,82.94H56.5C56.21,82.94 55.97,82.71 55.97,82.42V80.08ZM56.5,80.06C56.49,80.06 56.48,80.07 56.48,80.08V82.42C56.48,82.43 56.49,82.44 56.5,82.44H81.74C81.76,82.44 81.76,82.43 81.76,82.42V80.08C81.76,80.07 81.76,80.06 81.74,80.06H56.5Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M84.35,55.51C84.35,55.04 83.96,54.65 83.5,54.65H54.84C54.37,54.65 53.99,55.04 53.99,55.51V79.2C53.99,79.67 54.37,80.05 54.84,80.05H83.5C83.96,80.05 84.35,79.67 84.35,79.2V55.51Z"
android:fillType="evenOdd">
<aapt:attr name="android:fillColor">
<gradient
android:startX="86.99"
android:startY="76.75"
android:endX="80.17"
android:endY="65.38"
android:type="linear">
<item android:offset="0" android:color="#FFD2D2D2"/>
<item android:offset="1" android:color="#FFFFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M53.6,55.51C53.6,54.82 54.15,54.26 54.84,54.26H83.5C84.18,54.26 84.74,54.82 84.74,55.51V79.2C84.74,79.89 84.18,80.44 83.5,80.44H54.84C54.15,80.44 53.6,79.89 53.6,79.2V55.51ZM54.84,55.04C54.58,55.04 54.38,55.25 54.38,55.51V79.2C54.38,79.45 54.58,79.66 54.84,79.66H83.5C83.75,79.66 83.96,79.45 83.96,79.2V55.51C83.96,55.25 83.75,55.04 83.5,55.04H54.84Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M81.06,58.05C81.06,57.86 80.91,57.72 80.73,57.72H57.37C57.19,57.72 57.04,57.86 57.04,58.05V76.16C57.04,76.34 57.19,76.49 57.37,76.49H80.73C80.91,76.49 81.06,76.34 81.06,76.16V58.05Z"
android:fillColor="#003D88"
android:fillType="evenOdd"/>
<path
android:pathData="M56.85,58.05C56.85,57.76 57.09,57.53 57.37,57.53H80.73C81.01,57.53 81.24,57.76 81.24,58.05V76.16C81.24,76.44 81.01,76.67 80.73,76.67H57.37C57.09,76.67 56.85,76.44 56.85,76.16V58.05ZM57.37,57.9C57.29,57.9 57.23,57.97 57.23,58.05V76.16C57.23,76.24 57.29,76.3 57.37,76.3H80.73C80.81,76.3 80.87,76.24 80.87,76.16V58.05C80.87,57.97 80.81,57.9 80.73,57.9H57.37Z"
android:fillColor="#000000"
android:fillAlpha="0.93"
android:fillType="evenOdd"/>
</group>
</group>
</vector>

Binary file not shown.

After

(image error) Size: 1.5 KiB

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_banner_background"/>
<foreground android:drawable="@drawable/ic_banner_foreground"/>
</adaptive-icon>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

(image error) Size: 4.7 KiB

Binary file not shown.

After

(image error) Size: 1.7 KiB

Binary file not shown.

After

(image error) Size: 3.5 KiB

Binary file not shown.

After

(image error) Size: 2.9 KiB

Binary file not shown.

After

(image error) Size: 1.2 KiB

Binary file not shown.

After

(image error) Size: 2.1 KiB

Binary file not shown.

After

(image error) Size: 6.7 KiB

Binary file not shown.

After

(image error) Size: 2.5 KiB

Binary file not shown.

After

(image error) Size: 4.4 KiB

Binary file not shown.

After

(image error) Size: 11 KiB

Binary file not shown.

After

(image error) Size: 3.9 KiB

Binary file not shown.

After

(image error) Size: 7.5 KiB

Binary file not shown.

After

(image error) Size: 16 KiB

Binary file not shown.

After

(image error) Size: 5.7 KiB

Binary file not shown.

After

(image error) Size: 10 KiB

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_banner_background">#FFFFFF</color>
</resources>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MPD</string>
<string name="notification_title_mpd_running">Music Player Daemon is running</string>
<string name="notification_text_mpd_running">Touch for MPD options.</string>
<string name="toggle_button_run_on">MPD is running</string>
<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>
<string name="external_files_permission_request">MPD requires access to external files to play local music. Please grant the permission.</string>
<string name="title_open_app_info">Open app info</string>
<string name="mpd_load_failure_message">"Failed to load the native MPD library.
Report this problem to us, and include the following information:
SUPPORTED_ABIS=%1$s
PRODUCT=%2$s
FINGERPRINT=%3$s
error=%4$s"
</string>
<string name="stopped">Stopped</string>
<string name="running">Running</string>
<string name="stopMPD">Stop MPD</string>
<string name="startMPD">Start MPD</string>
</resources>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="red_500">#F44336</color>
<color name="red_900">#B71C1C</color>
<color name="green_300">#81C784</color>
<color name="green_700">#388E3C</color>
<color name="colorErrorOnLight">@color/red_900</color>
<color name="colorErrorOnDark">@color/red_500</color>
<color name="colorSuccessOnLight">@color/green_700</color>
<color name="colorSuccessOnDark">@color/green_300</color>
<attr name="appColorNegative" format="color|reference" />
<attr name="appColorPositive" format="color|reference" />
<style name="Theme.MPD" parent="android:Theme.Material.Light.NoActionBar">
<item name="appColorNegative">@color/colorErrorOnLight</item>
<item name="appColorPositive">@color/colorSuccessOnLight</item>
</style>
</resources>

7
android/build.gradle.kts Normal file

@ -0,0 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.google.devtools.ksp") version "1.9.22-1.0.16" apply false
alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false
alias(libs.plugins.dagger.hilt.android) apply false
}

@ -1,6 +1,7 @@
#!/usr/bin/env -S python3 -u
import os, os.path
import shutil
import sys, subprocess
if len(sys.argv) < 4:
@ -12,7 +13,7 @@ ndk_path = sys.argv[2]
android_abi = sys.argv[3]
configure_args = sys.argv[4:]
if not os.path.isfile(os.path.join(sdk_path, 'tools', 'android')):
if not os.path.isfile(os.path.join(sdk_path, 'licenses', 'android-sdk-license')):
print("SDK not found in", sdk_path, file=sys.stderr)
sys.exit(1)
@ -31,19 +32,11 @@ from build.toolchain import AndroidNdkToolchain
# a list of third-party libraries to be used by MPD on Android
from build.libs import *
thirdparty_libs = [
libmpdclient,
libogg,
opus,
flac,
libid3tag,
libmodplug,
wildmidi,
gme,
ffmpeg,
openssl,
curl,
libnfs,
boost,
]
# build the third-party libraries
@ -66,8 +59,24 @@ configure_args += [
'-Dandroid_ndk=' + ndk_path,
'-Dandroid_abi=' + android_abi,
'-Dandroid_strip=' + toolchain.strip,
'-Dopenssl:asm=disabled',
'-Dwrap_mode=forcefallback'
]
from build.meson import configure as run_meson
run_meson(toolchain, mpd_path, '.', configure_args)
subprocess.check_call(['/usr/bin/ninja'], env=toolchain.env)
ninja = shutil.which("ninja")
subprocess.check_call([ninja], env=toolchain.env)
subprocess.check_call([ninja, 'install'], env=toolchain.env)
print("""
-------------------------------------
## To build the android app:
# cd ../../android
# ./gradlew assemble{}Debug
## or, for a universal apk (includes both arm64-v8a and x86_64)
# ./gradlew assembleUniversalDebug
-------------------------------------
""".format(android_abi.capitalize()))

21
android/gradle.properties Normal file

@ -0,0 +1,21 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

@ -0,0 +1,41 @@
[versions]
androidGradlePlugin = "8.5.2"
accompanistPermissions = "0.33.2-alpha"
activityCompose = "1.10.0"
appcompat = "1.7.0"
composeBom = "2025.01.01"
composeSettingsStoragePreferences = "1.0.3"
composeSettingsUiM3 = "1.0.3"
daggerCompiler = "2.49"
hiltAndroid = "2.49"
hiltCompiler = "2.49"
lifecycleRuntimeKtx = "2.8.7"
media3Session = "1.5.1"
navigationCompose = "2.8.6"
kotlin = "1.9.22"
[libraries]
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycleRuntimeKtx" }
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" }
androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" }
androidx-material3 = { module = "androidx.compose.material3:material3" }
androidx-media3-session = { module = "androidx.media3:media3-session", version.ref = "media3Session" }
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
androidx-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" }
androidx-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
androidx-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
compose-settings-storage-preferences = { module = "com.github.alorma:compose-settings-storage-preferences", version.ref = "composeSettingsStoragePreferences" }
compose-settings-ui-m3 = { module = "com.github.alorma:compose-settings-ui-m3", version.ref = "composeSettingsUiM3" }
dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "daggerCompiler" }
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hiltCompiler" }
[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
dagger-hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hiltAndroid" }

Binary file not shown.

@ -0,0 +1,6 @@
#Sun Dec 17 15:00:03 CST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
android/gradlew vendored Executable file

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
android/gradlew.bat vendored Normal file

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

@ -0,0 +1,21 @@
javac = find_program('javac')
bridge_header = custom_target(
'org_musicpd_Bridge.h',
output: 'org_musicpd_Bridge.h',
input: [
'../app/src/main/java/org/musicpd/Bridge.java',
],
command: [
javac,
'-source', '1.8', '-target', '1.8',
'-Xlint:-options',
'-cp', join_paths(android_sdk_platform_dir, 'android.jar'),
# not interested in *.class, we only want the JNI header
'-d', '@PRIVATE_DIR@',
'-h', '@OUTDIR@',
'@INPUT@',
],
)

@ -1,24 +0,0 @@
#!/bin/sh -e
S=`dirname "$0"`
AAPT=$1
BASE_JAR=$2
JAVA_PKG=$3
JAVA_PKG_PATH=$4
APK_FILE="$5"
D=`dirname "$APK_FILE"`
rm -rf "$D/res"
mkdir -p "$D/res/drawable" "$D/src"
cp "$D/icon.png" "$D/notification_icon.png" "$D/res/drawable/"
"$AAPT" package -f -m --auto-add-overlay \
--custom-package "$JAVA_PKG" \
-M "$S/AndroidManifest.xml" \
-S "$D/res" \
-S "$S/res" \
-J "$D/src" \
-I "$BASE_JAR" \
-F "$D/resources.apk"
cp "$D/src/$JAVA_PKG_PATH/R.java" "$D/"

@ -5,136 +5,13 @@ android_ndk = get_option('android_ndk')
android_sdk = get_option('android_sdk')
android_abi = get_option('android_abi')
android_sdk_build_tools_version = '29.0.3'
android_sdk_platform = 'android-29'
android_sdk_build_tools_version = '34.0.0'
android_sdk_platform = 'android-34'
android_build_tools_dir = join_paths(android_sdk, 'build-tools', android_sdk_build_tools_version)
android_sdk_platform_dir = join_paths(android_sdk, 'platforms', android_sdk_platform)
android_aidl = join_paths(android_build_tools_dir, 'aidl')
android_aapt = join_paths(android_build_tools_dir, 'aapt')
android_dx = join_paths(android_build_tools_dir, 'dx')
android_zipalign = join_paths(android_build_tools_dir, 'zipalign')
javac = find_program('javac')
apksigner = find_program('apksigner')
rsvg_convert = find_program('rsvg-convert')
convert = find_program('convert')
zip = find_program('zip')
android_gradlew = join_paths(meson.current_source_dir(), 'gradlew')
common_cppflags += '-I' + join_paths(meson.current_build_dir(), 'include')
#
# AIDL
#
IMainCallback_java = custom_target(
'IMainCallback.java',
output: 'IMainCallback.java',
input: join_paths(meson.current_source_dir(), 'src', 'IMainCallback.aidl'),
command: [
join_paths(meson.current_source_dir(), 'run-aidl.sh'),
android_aidl,
'@INPUT@',
'@OUTPUT@',
join_paths(meson.current_build_dir(), 'src'),
android_package_path,
],
)
IMain_java = custom_target(
'IMain.java',
output: 'IMain.java',
input: join_paths(meson.current_source_dir(), 'src', 'IMain.aidl'),
depends: IMainCallback_java,
command: [
join_paths(meson.current_source_dir(), 'run-aidl.sh'),
android_aidl,
'@INPUT@',
'@OUTPUT@',
join_paths(meson.current_build_dir(), 'src'),
android_package_path,
],
)
#
# Resources
#
android_icon = custom_target(
'Android icon',
output: 'icon.png',
input: '../mpd.svg',
command: [
rsvg_convert, '--width=48', '--height=48', '@INPUT@', '-o', '@OUTPUT@',
],
)
android_notification_icon = custom_target(
'Android notification icon',
output: 'notification_icon.png',
input: android_icon,
command: [
convert, '@INPUT@', '-colorspace', 'Gray', '-gamma', '2.2', '@OUTPUT@',
],
)
resources_apk = custom_target(
'resources.apk',
output: ['resources.apk', 'R.java'],
input: [
'res/layout/custom_notification_gb.xml',
'res/layout/log_item.xml',
'res/layout/settings.xml',
'res/values/strings.xml',
android_icon,
android_notification_icon,
],
command: [
join_paths(meson.current_source_dir(), 'make-resources-apk.sh'),
android_aapt,
join_paths(android_sdk_platform_dir, 'android.jar'),
android_package,
android_package_path,
'@OUTPUT0@',
],
)
#
# Compile Java
#
classes_jar = custom_target(
'classes.jar',
output: 'classes.jar',
input: [
'src/Bridge.java',
'src/Loader.java',
'src/Main.java',
'src/Receiver.java',
'src/Settings.java',
IMain_java,
IMainCallback_java,
resources_apk[1],
],
command: [
join_paths(meson.current_source_dir(), 'run-javac.sh'),
javac,
join_paths(android_sdk_platform_dir, 'android.jar'),
android_package_path,
zip,
'@OUTPUT@',
'@INPUT@',
],
)
classes_dex = custom_target(
'classes.dex',
output: 'classes.dex',
input: classes_jar,
command: [
android_dx,
'--dex', '--output', '@OUTPUT@',
'@INPUT@',
],
)
subdir('include')

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:typeface="monospace" />

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ToggleButton
android:id="@+id/run"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textOn="@string/toggle_button_run_on"
android:textOff="@string/toggle_button_run_off" />
<CheckBox
android:id="@+id/run_on_boot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/checkbox_run_on_boot" />
<CheckBox
android:id="@+id/wakelock"
android:layout_width="match_parent"
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"
android:layout_height="wrap_content" />
<ListView
android:id="@+id/log_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dip" />
</LinearLayout>

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MPD</string>
<string name="notification_title_mpd_running">Music Player Daemon is running</string>
<string name="notification_text_mpd_running">Touch for MPD options.</string>
<string name="toggle_button_run_on">MPD is running</string>
<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>

@ -1,12 +0,0 @@
#!/bin/sh -e
AIDL=$1
SRC=$2
DST=$3
GENSRC=$4
JAVA_PKG_PATH=$5
mkdir -p "$GENSRC/$JAVA_PKG_PATH"
cp "$SRC" "$GENSRC/$JAVA_PKG_PATH/"
"$AIDL" -I"$GENSRC" -o"$GENSRC" "$GENSRC/$JAVA_PKG_PATH/`basename $SRC`"
exec cp "$GENSRC/$JAVA_PKG_PATH/`basename $DST`" "$DST"

@ -1,22 +0,0 @@
#!/bin/sh -e
JAVAC=$1
CLASSPATH=$2
JAVA_PKG_PATH=$3
ZIP=$4
JARFILE=`realpath "$5"`
shift 5
D=`dirname "$JARFILE"`
GENSRC="$D/src"
GENCLASS="$D/classes"
GENINCLUDE="$D/include"
mkdir -p "$GENSRC/$JAVA_PKG_PATH"
"$JAVAC" -source 1.7 -target 1.7 -Xlint:-options \
-cp "$CLASSPATH" \
-h "$GENINCLUDE" \
-d "$GENCLASS" \
"$@"
cd "$GENCLASS"
zip -q -r "$JARFILE" .

@ -0,0 +1,18 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "MPD"
include(":app")

@ -1,37 +0,0 @@
/*
* Copyright 2003-2021 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.musicpd;
import android.content.Context;
/**
* Bridge to native code.
*/
public class Bridge {
/* used by jni */
public interface LogListener {
public void onLog(int priority, String msg);
}
public static native void run(Context context, LogListener logListener);
public static native void shutdown();
public static native void pause();
}

@ -1,39 +0,0 @@
/*
* Copyright 2003-2021 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.musicpd;
import android.util.Log;
public class Loader {
private static final String TAG = "MPD";
public static boolean loaded = false;
public static String error;
static {
try {
System.loadLibrary("mpd");
loaded = true;
} catch (UnsatisfiedLinkError e) {
Log.e(TAG, e.getMessage());
error = e.getMessage();
}
}
}

@ -1,475 +0,0 @@
/*
* Copyright 2003-2021 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.musicpd;
import android.annotation.TargetApi;
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;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.widget.RemoteViews;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Main extends Service implements Runnable {
private static final String TAG = "Main";
private static final String REMOTE_ERROR = "MPD process was killed";
private static final int MAIN_STATUS_ERROR = -1;
private static final int MAIN_STATUS_STOPPED = 0;
private static final int MAIN_STATUS_STARTED = 1;
private static final int MSG_SEND_STATUS = 0;
private static final int MSG_SEND_LOG = 1;
private Thread mThread = null;
private int mStatus = MAIN_STATUS_STOPPED;
private boolean mAbort = false;
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 {
private Main mService;
MainStub(Main service) {
mService = service;
}
public void start() {
mService.start();
}
public void stop() {
mService.stop();
}
public void setPauseOnHeadphonesDisconnect(boolean enabled) {
mService.setPauseOnHeadphonesDisconnect(enabled);
}
public void setWakelockEnabled(boolean enabled) {
mService.setWakelockEnabled(enabled);
}
public boolean isRunning() {
return mService.isRunning();
}
public void registerCallback(IMainCallback cb) {
mService.registerCallback(cb);
}
public void unregisterCallback(IMainCallback cb) {
mService.unregisterCallback(cb);
}
}
private synchronized void sendMessage(int what, int arg1, int arg2, Object obj) {
int i = mCallbacks.beginBroadcast();
while (i > 0) {
i--;
final IMainCallback cb = mCallbacks.getBroadcastItem(i);
try {
switch (what) {
case MSG_SEND_STATUS:
switch (arg1) {
case MAIN_STATUS_ERROR:
cb.onError((String)obj);
break;
case MAIN_STATUS_STOPPED:
cb.onStopped();
break;
case MAIN_STATUS_STARTED:
cb.onStarted();
break;
}
break;
case MSG_SEND_LOG:
cb.onLog(arg1, (String) obj);
break;
}
} catch (RemoteException e) {
}
}
mCallbacks.finishBroadcast();
}
private Bridge.LogListener mLogListener = new Bridge.LogListener() {
@Override
public void onLog(int priority, String msg) {
sendMessage(MSG_SEND_LOG, priority, 0, msg);
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
start();
if (intent != null && intent.getBooleanExtra("wakelock", false))
setWakelockEnabled(true);
return START_STICKY;
}
@Override
public void run() {
if (!Loader.loaded) {
final String error = "Failed to load the native MPD libary.\n" +
"Report this problem to us, and include the following information:\n" +
"SUPPORTED_ABIS=" + String.join(", ", Build.SUPPORTED_ABIS) + "\n" +
"PRODUCT=" + Build.PRODUCT + "\n" +
"FINGERPRINT=" + Build.FINGERPRINT + "\n" +
"error=" + Loader.error;
setStatus(MAIN_STATUS_ERROR, error);
stopSelf();
return;
}
synchronized (this) {
if (mAbort)
return;
setStatus(MAIN_STATUS_STARTED, null);
}
Bridge.run(this, mLogListener);
setStatus(MAIN_STATUS_STOPPED, null);
}
private synchronized void setStatus(int status, String error) {
mStatus = status;
mError = error;
sendMessage(MSG_SEND_STATUS, mStatus, 0, mError);
}
private Notification.Builder createNotificationBuilderWithChannel() {
final NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null)
return null;
final String id = "org.musicpd";
final String name = "MPD service";
final int importance = 3; /* NotificationManager.IMPORTANCE_DEFAULT */
try {
Class<?> ncClass = Class.forName("android.app.NotificationChannel");
Constructor<?> ncCtor = ncClass.getConstructor(String.class, CharSequence.class, int.class);
Object nc = ncCtor.newInstance(id, name, importance);
Method nmCreateNotificationChannelMethod =
NotificationManager.class.getMethod("createNotificationChannel", ncClass);
nmCreateNotificationChannelMethod.invoke(notificationManager, nc);
Constructor nbCtor = Notification.Builder.class.getConstructor(Context.class, String.class);
return (Notification.Builder) nbCtor.newInstance(this, id);
} catch (Exception e)
{
Log.e(TAG, "error creating the NotificationChannel", e);
return null;
}
}
private void start() {
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");
final PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
mainIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification.Builder nBuilder;
if (Build.VERSION.SDK_INT >= 26 /* Build.VERSION_CODES.O */)
{
nBuilder = createNotificationBuilderWithChannel();
if (nBuilder == null)
return;
}
else
nBuilder = new Notification.Builder(this);
Notification notification = nBuilder.setContentTitle(getText(R.string.notification_title_mpd_running))
.setContentText(getText(R.string.notification_text_mpd_running))
.setSmallIcon(R.drawable.notification_icon)
.setContentIntent(contentIntent)
.build();
mThread = new Thread(this);
mThread.start();
startForeground(R.string.notification_title_mpd_running, notification);
startService(new Intent(this, Main.class));
}
private void stop() {
if (mThread != null) {
if (mThread.isAlive()) {
synchronized (this) {
if (mStatus == MAIN_STATUS_STARTED)
Bridge.shutdown();
else
mAbort = true;
}
}
try {
mThread.join();
mThread = null;
mAbort = false;
} catch (InterruptedException ie) {}
}
setWakelockEnabled(false);
stopForeground(true);
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);
mWakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakelock.acquire();
Log.d(TAG, "Wakelock acquired");
} else if (!enabled && mWakelock != null) {
mWakelock.release();
mWakelock = null;
Log.d(TAG, "Wakelock released");
}
}
private boolean isRunning() {
return mThread != null && mThread.isAlive();
}
private void registerCallback(IMainCallback cb) {
if (cb != null) {
mCallbacks.register(cb);
sendMessage(MSG_SEND_STATUS, mStatus, 0, mError);
}
}
private void unregisterCallback(IMainCallback cb) {
if (cb != null) {
mCallbacks.unregister(cb);
}
}
/*
* Client that bind the Main Service in order to send commands and receive callback
*/
public static class Client {
public interface Callback {
public void onStarted();
public void onStopped();
public void onError(String error);
public void onLog(int priority, String msg);
}
private boolean mBound = false;
private final Context mContext;
private Callback mCallback;
private IMain mIMain = null;
private final IMainCallback.Stub mICallback = new IMainCallback.Stub() {
@Override
public void onStopped() throws RemoteException {
mCallback.onStopped();
}
@Override
public void onStarted() throws RemoteException {
mCallback.onStarted();
}
@Override
public void onError(String error) throws RemoteException {
mCallback.onError(error);
}
@Override
public void onLog(int priority, String msg) throws RemoteException {
mCallback.onLog(priority, msg);
}
};
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (this) {
mIMain = IMain.Stub.asInterface(service);
try {
if (mCallback != null)
mIMain.registerCallback(mICallback);
} catch (RemoteException e) {
if (mCallback != null)
mCallback.onError(REMOTE_ERROR);
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (mCallback != null)
mCallback.onError(REMOTE_ERROR);
}
};
public Client(Context context, Callback cb) throws IllegalArgumentException {
if (context == null)
throw new IllegalArgumentException("Context can't be null");
mContext = context;
mCallback = cb;
mBound = mContext.bindService(new Intent(mContext, Main.class), mServiceConnection, Context.BIND_AUTO_CREATE);
}
public boolean start() {
synchronized (this) {
if (mIMain != null) {
try {
mIMain.start();
return true;
} catch (RemoteException e) {
}
}
return false;
}
}
public boolean stop() {
synchronized (this) {
if (mIMain != null) {
try {
mIMain.stop();
return true;
} catch (RemoteException e) {
}
}
return false;
}
}
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) {
try {
mIMain.setWakelockEnabled(enabled);
return true;
} catch (RemoteException e) {
}
}
return false;
}
}
public boolean isRunning() {
synchronized (this) {
if (mIMain != null) {
try {
return mIMain.isRunning();
} catch (RemoteException e) {
}
}
return false;
}
}
public void release() {
if (mBound) {
synchronized (this) {
if (mIMain != null && mICallback != null) {
try {
if (mCallback != null)
mIMain.unregisterCallback(mICallback);
} catch (RemoteException e) {
}
}
}
mBound = false;
mContext.unbindService(mServiceConnection);
}
}
}
/*
* start Main service without any callback
*/
public static void start(Context context, boolean 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);
}
}

@ -1,42 +0,0 @@
/*
* Copyright (C) 2003-2021 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.musicpd;
import android.content.BroadcastReceiver;
import android.content.Context;
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);
}
}
}
}

@ -1,308 +0,0 @@
/*
* Copyright 2003-2021 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.musicpd;
import java.util.LinkedList;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ToggleButton;
public class Settings extends Activity {
private static final String TAG = "Settings";
private Main.Client mClient;
private TextView mTextStatus;
private ToggleButton mRunButton;
private boolean mFirstRun;
private LinkedList<String> mLogListArray = new LinkedList<String>();
private ListView mLogListView;
private ArrayAdapter<String> mLogListAdapter;
private static final int MAX_LOGS = 500;
private static final int MSG_ERROR = 0;
private static final int MSG_STOPPED = 1;
private static final int MSG_STARTED = 2;
private static final int MSG_LOG = 3;
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);
}
public static void putBoolean(Context context, String key, boolean value) {
final SharedPreferences prefs = get(context);
if (prefs == null)
return;
final Editor editor = prefs.edit();
editor.putBoolean(key, value);
editor.apply();
}
public static boolean getBoolean(Context context, String key, boolean defValue) {
final SharedPreferences prefs = get(context);
return prefs != null ? prefs.getBoolean(key, defValue) : defValue;
}
}
private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_ERROR:
Log.d(TAG, "onError");
mClient.release();
connectClient();
mRunButton.setEnabled(false);
mRunButton.setChecked(false);
mTextStatus.setText((String)msg.obj);
mFirstRun = true;
break;
case MSG_STOPPED:
Log.d(TAG, "onStopped");
mRunButton.setEnabled(true);
if (!mFirstRun && Preferences.getBoolean(Settings.this, Preferences.KEY_RUN_ON_BOOT, false))
mRunButton.setChecked(true);
else
mRunButton.setChecked(false);
mFirstRun = true;
mTextStatus.setText("");
break;
case MSG_STARTED:
Log.d(TAG, "onStarted");
mRunButton.setChecked(true);
mFirstRun = true;
mTextStatus.setText("MPD service started");
break;
case MSG_LOG:
if (mLogListArray.size() > MAX_LOGS)
mLogListArray.remove(0);
String priority;
switch (msg.arg1) {
case Log.DEBUG:
priority = "D";
break;
case Log.ERROR:
priority = "E";
break;
case Log.INFO:
priority = "I";
break;
case Log.VERBOSE:
priority = "V";
break;
case Log.WARN:
priority = "W";
break;
default:
priority = "";
}
mLogListArray.add(priority + "/ " + (String)msg.obj);
mLogListAdapter.notifyDataSetChanged();
break;
}
return true;
}
});
private final OnCheckedChangeListener mOnRunChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mClient != null) {
if (isChecked) {
mClient.start();
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();
}
}
}
};
private final OnCheckedChangeListener mOnRunOnBootChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Preferences.putBoolean(Settings.this, Preferences.KEY_RUN_ON_BOOT, isChecked);
if (isChecked && mClient != null && !mRunButton.isChecked())
mRunButton.setChecked(true);
}
};
private final OnCheckedChangeListener mOnWakelockChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Preferences.putBoolean(Settings.this, Preferences.KEY_WAKELOCK, isChecked);
if (mClient != null && mClient.isRunning())
mClient.setWakelockEnabled(isChecked);
}
};
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
permissions - it will cause MPD to quit
immediately; we should request permissions when we
need them, but implementing that is complicated, so
for now, we do it here to give users a quick
solution for the problem */
requestAllPermissions();
setContentView(R.layout.settings);
mRunButton = (ToggleButton) findViewById(R.id.run);
mRunButton.setOnCheckedChangeListener(mOnRunChangeListener);
mTextStatus = (TextView) findViewById(R.id.status);
mLogListAdapter = new ArrayAdapter<String>(this, R.layout.log_item, mLogListArray);
mLogListView = (ListView) findViewById(R.id.log_list);
mLogListView.setAdapter(mLogListAdapter);
mLogListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
CheckBox checkbox = (CheckBox) findViewById(R.id.run_on_boot);
checkbox.setOnCheckedChangeListener(mOnRunOnBootChangeListener);
if (Preferences.getBoolean(this, Preferences.KEY_RUN_ON_BOOT, false))
checkbox.setChecked(true);
checkbox = (CheckBox) findViewById(R.id.wakelock);
checkbox.setOnCheckedChangeListener(mOnWakelockChangeListener);
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);
}
private void checkRequestPermission(String permission) {
if (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED)
return;
try {
this.requestPermissions(new String[]{permission}, 0);
} catch (Exception e) {
Log.e(TAG, "requestPermissions(" + permission + ") failed",
e);
}
}
private void requestAllPermissions() {
if (android.os.Build.VERSION.SDK_INT < 23)
/* we don't need to request permissions on
this old Android version */
return;
/* starting with Android 6.0, we need to explicitly
request all permissions before using them;
mentioning them in the manifest is not enough */
checkRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
}
private void connectClient() {
mClient = new Main.Client(this, new Main.Client.Callback() {
private void removeMessages() {
/* don't remove log messages */
mHandler.removeMessages(MSG_STOPPED);
mHandler.removeMessages(MSG_STARTED);
mHandler.removeMessages(MSG_ERROR);
}
@Override
public void onStopped() {
removeMessages();
mHandler.sendEmptyMessage(MSG_STOPPED);
}
@Override
public void onStarted() {
removeMessages();
mHandler.sendEmptyMessage(MSG_STARTED);
}
@Override
public void onError(String error) {
removeMessages();
mHandler.sendMessage(Message.obtain(mHandler, MSG_ERROR, error));
}
@Override
public void onLog(int priority, String msg) {
mHandler.sendMessage(Message.obtain(mHandler, MSG_LOG, priority, 0, msg));
}
});
}
@Override
protected void onStart() {
mFirstRun = false;
connectClient();
super.onStart();
}
@Override
protected void onStop() {
mClient.release();
mClient = null;
super.onStop();
}
}

@ -10,4 +10,4 @@ ROOT=`dirname "$BIN"`
export PKG_CONFIG_DIR=
export PKG_CONFIG_LIBDIR="${ROOT}/lib/pkgconfig:${ROOT}/share/pkgconfig"
exec /usr/bin/pkg-config "$@"
exec pkg-config "$@"

3
doc/_static/css/custom.css vendored Normal file

@ -0,0 +1,3 @@
/*
* css to override sphinx theme
*/

@ -30,7 +30,7 @@ master_doc = 'index'
# General information about the project.
project = 'Music Player Daemon'
copyright = '2003-2021 The Music Player Daemon Project'
copyright = '2003-2025 The Music Player Daemon Project'
author = 'Max Kellermann'
# The version info for the project you're documenting, acts as replacement for
@ -103,14 +103,27 @@ todo_include_todos = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'classic'
html_theme = 'sphinx_rtd_theme'
try:
__import__(html_theme)
except ModuleNotFoundError:
import sys
print(f"Warning: Sphinx theme {html_theme!r} not available, falling back to the default theme", file=sys.stderr)
del html_theme
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
html_theme_options = {"sidebarwidth": "300px"}
html_theme_options = {
'navigation_depth': -1,
'sticky_navigation': False,
'includehidden': True,
'prev_next_buttons_location': 'both',
'github_url': "https://github.com/MusicPlayerDaemon/"
}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
@ -140,6 +153,10 @@ html_theme_options = {"sidebarwidth": "300px"}
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_css_files = [
'css/custom.css',
]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.

@ -12,7 +12,7 @@ Code Style
* indent with tabs (width 8)
* don't write CPP when you can write C++: use inline functions and constexpr instead of macros
* comment your code, document your APIs
* the code should be C++17 compliant, and must compile with :program:`GCC` 8 and :program:`clang` 5
* the code should be C++20 compliant, and must compile with :program:`GCC` 12 and :program:`clang` 14
* all code must be exception-safe
* classes and functions names use CamelCase; variables are lower-case with words separated by underscore

@ -2038,9 +2038,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = GCC_CHECK_VERSION(major,minor)=0 \
CLANG_OR_GCC_VERSION(major,minor)=0 \
GCC_OLDER_THAN(major,minor)=0
PREDEFINED = GCC_CHECK_VERSION(major,minor)=0
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The

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