Compare commits

...

53 Commits

Author SHA1 Message Date
Max Kellermann
e239009295 release v0.21.10 2019-06-05 22:32:32 +02:00
Max Kellermann
3fae2150f5 decoder/OpusReader: return StringView
Since we now don't duplicate all items, we can easily remove the 64kB
limit from OpusReader::ReadString() and instead silently ignore and
skip all strings which are longer than 4 kB.

This fixes a tag duplication bug with Opus file containing a very long
`METADATA_BLOCK_PICTURE` tag, which occurred because the Opus plugin
returned false after parsing all tags, and then the MPD core fell back
to FFmpeg which scanned the tags again.
2019-06-05 22:19:35 +02:00
cathugger
f9ca2f52c1 output/httpd: reject some well-known request paths
Return `404 not found` for some common well-known paths, as clients requesting them usually do that automatically and don't expect endless audio stram.

Closes #572
2019-06-05 21:53:46 +02:00
cathugger
4b81cf0c2c output/httpd: use strncmp instead of memcmp
memcmp use may result in out of bounds access
2019-06-05 21:53:46 +02:00
Max Kellermann
e7acbf112c output/httpd: fix indent 2019-06-05 21:53:43 +02:00
Max Kellermann
304d45b551 Revert "player/Thread: remove unnecessary "pipe" check"
This reverts commit ff3e2c0514.  The
check was necessary, after all, because this is what checked whether
the decoder had finished the current or the next song.

> The "queued" flag can only possibly be set if the decoder is still
> decoding the current song or if the decoder is stopped.

That was wrong because ProcessCommand() sets `queued=true` and also
starts the decoder (if it was idle).

> This is also what the following assert() checks.

That was also wrong, because the assert() has two conditions.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/566
2019-05-31 17:23:12 +02:00
Max Kellermann
0f488dcecf doc/protocol.rst: binary responses do have a newline after all
Closes https://github.com/MusicPlayerDaemon/MPD/issues/568
2019-05-31 16:47:41 +02:00
Max Kellermann
17039aec70 doc/user.rst: more heading corrections
According to http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#sections
2019-05-31 16:30:06 +02:00
Max Kellermann
fb6cb07912 doc/developer.rst: remove outdated section about the clang static analyzer 2019-05-31 16:27:43 +02:00
Max Kellermann
e9e0e02db3 doc/user.rst: use ".. note:" 2019-05-31 16:26:52 +02:00
Max Kellermann
03507037e8 increment version number to 0.21.10 2019-05-31 16:16:56 +02:00
Max Kellermann
66a8fac25e release v0.21.9 2019-05-20 17:10:58 +02:00
Max Kellermann
1b902e00b4 doc/protocol.rst: several clarifications
Closes https://github.com/MusicPlayerDaemon/MPD/issues/340
2019-05-20 17:06:20 +02:00
Max Kellermann
923e66738c player/Thread: fix "single" mode race condition
If the decoder finishes decoding the current song between the two
IsIdle() checks, MPD stops playback instead of starting the decoder
for the next song.

This is usually not visible problem, because the main thread restarts
it via playlist::ResumePlayback(), but that way it, ignores "single"
mode.

As a workaround, this commit adds another "queued" check which
re-enters the player loop and checks again whether to start the
decoder.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/556
2019-05-20 16:22:01 +02:00
Max Kellermann
ff3e2c0514 player/Thread: remove unnecessary "pipe" check
The "queued" flag can only possibly be set if the decoder is still
decoding the current song or if the decoder is stopped.  This is also
what the following assert() checks.  This check was not necessary.
2019-05-20 16:20:59 +02:00
Max Kellermann
6922a2f55e input/buffered: check error in IsAvailable() 2019-05-17 12:43:45 +02:00
Max Kellermann
ca5a400dbe input/buffered: rethrow read_error in Check() 2019-05-16 22:08:33 +02:00
Max Kellermann
63fe4d1d17 input/buffered: wake up client thread on seek error 2019-05-16 22:05:25 +02:00
Max Kellermann
ca06d9d3bf input/buffered: fix deadlock bug 2019-05-16 21:11:03 +02:00
Max Kellermann
ed2db04f43 doc/mpd.conf.5: remove ALSA specific documentation
ALSA is just one out of many output plugins, and detailed plugin
documentation should only live in the user manual, without having
duplicates in the (brief) manpage.

Also move "mixer_type" to the "optional audio output parameters"
section; it is a generic option, not specific to ALSA.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/552
2019-05-13 22:51:48 +02:00
Max Kellermann
de0afa0e08 doc/mpd.conf.5: fix section indent 2019-05-13 22:51:45 +02:00
Max Kellermann
f0d3227d7b doc/protocol.rst: add references to audio_output_format 2019-05-13 22:46:23 +02:00
Max Kellermann
fb07a7cecc doc/user.rst: move audio format spec to section "Global Audio Format" 2019-05-13 22:39:49 +02:00
Max Kellermann
c6b08a4d48 doc/user.rst: add reference to audio_output_format 2019-05-13 22:39:44 +02:00
Max Kellermann
040e87ad8d doc/user.rst: more markup 2019-05-13 22:36:19 +02:00
Max Kellermann
d5521ead56 doc/user.rst: add missing space 2019-05-13 22:36:19 +02:00
Max Kellermann
f8468451c9 android/AndroidManifest.xml: increment versionCode after hotfix upload 2019-05-04 13:25:05 +02:00
Max Kellermann
65df6ca14e android/Settings: request READ_EXTERNAL_STORAGE permission
Using this API function requires SDK level 23.
2019-05-04 07:29:41 +02:00
Max Kellermann
36dec47bf7 android/build.py: link ARMv7 binary with libunwind
Fixes nullptr dereference when an exception gets thrown because there
is no ".eh_frame" section for unwinding.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/543
2019-05-03 20:15:50 +02:00
Max Kellermann
478cedcadf increment version number to 0.21.9 2019-05-03 20:15:33 +02:00
Max Kellermann
cabcbb059d release v0.21.8 2019-04-23 14:35:14 +02:00
Max Kellermann
5e21b2db3c doc/protocol.rst: "list file" is deprecated
Closes https://github.com/MusicPlayerDaemon/MPD/issues/526
2019-04-23 14:29:42 +02:00
Max Kellermann
3a0d6d96c1 input/smbclient: wrap in MaybeBufferedInputStream
This enables the input buffer for remote files and caches file
contents in MPD.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/376
2019-04-23 14:08:27 +02:00
Max Kellermann
f39d2d33c0 python/build/libs.py: upgrade Boost to 1.70.0 2019-04-23 14:08:27 +02:00
Max Kellermann
ead3dc6a92 LocateUri: pass URI plugin kind, optionally disables plugin verify
Commit b3a458338a added a LocateUri()
call to several playlist commands, which applied InputPlugin URI
scheme verification to playlist URIs.  This broke the SoundCloud
playlist plugin which uses "soundcloud://" URIs for which no input
plugin exists.

This commit allows the caller to specify the kind of plugin which
shall be used to verify the URI.  Right now, only "input" is
implemented; "storage" uses the "input" verification for now; and
"playlist" has no verification at all (for now).

Closes https://github.com/MusicPlayerDaemon/MPD/issues/528
2019-04-18 10:03:15 +02:00
Max Kellermann
7d814cc899 neighbor/smbclient: fix double smbc_closedir() call
There is already one call in ReadServers(), which is the correct place
to do it.
2019-04-18 09:40:56 +02:00
Max Kellermann
f5b4606c09 .travis.yml: switch to another PPA for a newer ninja version
Fixes Travis failure with Meson 0.50:

 ERROR: Could not detect Ninja v1.5 or newer
2019-04-18 09:40:30 +02:00
Max Kellermann
d6dbf64efb CommandLine: fix another build failure with -Ddatabase=false
Split several printf() calls to make it easier to deal with all those
#ifdefs.
2019-04-18 09:20:12 +02:00
Eugene Gorodinsky
8d18b4c24b Fix meson.build to work properly with '-Ddatabase=false' 2019-04-18 08:55:13 +02:00
Max Kellermann
fe8621906d systemd: add user socket unit
Copy the system socket unit to the "user" directory.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/530
2019-04-10 16:37:13 +02:00
Max Kellermann
b4fcbdb235 systemd/socket: use %t instead of hard-coding /run
This allows using the file as a user unit, where "%t" maps to
"$XDG_RUNTIME_DIR".

Proposed in https://github.com/MusicPlayerDaemon/MPD/issues/530
2019-04-10 16:34:40 +02:00
Max Kellermann
f4b5a28596 doc/protocol: mention that stickers are only implemented for songs
Closes https://github.com/MusicPlayerDaemon/MPD/issues/524
2019-04-10 16:33:17 +02:00
Max Kellermann
6cbd77fc57 doc/protocol.rst: mention "in seconds" where it was missing
Closes https://github.com/MusicPlayerDaemon/MPD/issues/523
2019-04-10 16:30:26 +02:00
cotko
1bc78e9f2c Fid move doc args 2019-04-10 13:16:58 +02:00
Max Kellermann
cb6282e0a7 doc/developer.rst: remove mailing list, refer to GitHub instead 2019-04-10 11:36:03 +02:00
Max Kellermann
f6941f9a44 event/SocketMonitor: don't cancel if OnSocketReady() returns false
Expect OnSocketReady() to cancel events.  If it returns false, the
SocketMonitor may be destructed already.  This fixes a use-after-free
bug in the "httpd" output plugin.
2019-04-04 10:24:58 +02:00
Max Kellermann
d2eb4df8fc event/{Fully,}BufferedSocket: add more API documentation 2019-04-04 10:24:58 +02:00
Max Kellermann
df33a898d7 zeroconf/Bonjour: fix OnSocketReady() return value
Keep the SocketMonitor registered.  This wrong return value was added
6 years ago in commit 72cf8dd8a0, andd
apparently, nobody ever noticed.
2019-04-04 10:24:29 +02:00
Max Kellermann
325c7b8e8b output/httpd: close client connection on error
This missing piece probably never really hurt, because
HttpdClient::OnSocketClosed() would be called right after a socket
error, but it's better to be explicit about closing on error.
2019-04-04 09:39:22 +02:00
Max Kellermann
380656d8c9 output/httpd: add missing mutex lock 2019-04-03 22:53:03 +02:00
Max Kellermann
9111bc2c21 output/httpd: add more API documentation about locking 2019-04-03 22:49:25 +02:00
Max Kellermann
37b54179d8 net/IPv[46]Address: add cast to void* to fix GCC9 build failure
Fixes:

 src/net/IPv4Address.hxx: In member function 'constexpr IPv4Address::operator SocketAddress() const':
 src/net/IPv4Address.hxx:171:24: error: a reinterpret_cast is not a constant expression
   171 |   return SocketAddress((const struct sockaddr *)&address,
       |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 src/net/IPv6Address.hxx: In member function 'constexpr IPv6Address::operator SocketAddress() const':
 src/net/IPv6Address.hxx:138:24: error: a reinterpret_cast is not a constant expression
   138 |   return SocketAddress((const struct sockaddr *)&address,
       |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Closes https://github.com/MusicPlayerDaemon/MPD/issues/522
2019-04-03 16:59:53 +02:00
Max Kellermann
511826763a increment version number to 0.21.8 2019-04-03 12:27:18 +02:00
42 changed files with 485 additions and 305 deletions

View File

@@ -9,7 +9,7 @@ matrix:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- sourceline: 'ppa:mhier/libboost-latest' - sourceline: 'ppa:mhier/libboost-latest'
- sourceline: 'ppa:saiarcot895/chromium-dev' # for ninja-build - sourceline: 'ppa:mstipicevic/ninja-build-1-7-2'
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson) - sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
packages: packages:
- g++-6 - g++-6
@@ -34,7 +34,7 @@ matrix:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- sourceline: 'ppa:mhier/libboost-latest' - sourceline: 'ppa:mhier/libboost-latest'
- sourceline: 'ppa:saiarcot895/chromium-dev' # for ninja-build - sourceline: 'ppa:mstipicevic/ninja-build-1-7-2'
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson) - sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
packages: packages:
- g++-8 - g++-8

29
NEWS
View File

@@ -1,3 +1,32 @@
ver 0.21.10 (2019/06/05)
* decoder
- opus: fix duplicate tags
* output
- httpd: reject some well-known URIs
* fix crash bug (0.21.9 regression)
ver 0.21.9 (2019/05/20)
* input
- buffer: fix deadlock bug
* Android
- fix crash on ARMv7
- request storage permission on Android 6+
* fix spurious "single" mode bug
ver 0.21.8 (2019/04/23)
* input
- smbclient: download to buffer instead of throttling transfer
* output
- httpd: add missing mutex lock
- httpd: fix use-after-free bug
* playlist
- soundcloud: fix "Unsupported URI scheme" (0.21.6 regression)
* fix Bonjour bug
* fix build failure with GCC 9
* fix build failure with -Ddatabase=false
* systemd: add user socket unit
* doc: "list file" is deprecated
ver 0.21.7 (2019/04/03) ver 0.21.7 (2019/04/03)
* input * input
- qobuz/tidal: scan tags when loading a playlist - qobuz/tidal: scan tags when loading a playlist

View File

@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd" package="org.musicpd"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="29" android:versionCode="33"
android:versionName="0.21.7"> android:versionName="0.21.10">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>

View File

@@ -138,6 +138,12 @@ class AndroidNdkToolchain:
libstdcxx_ldflags = libstdcxx_flags + ' -L' + libcxx_libs_path libstdcxx_ldflags = libstdcxx_flags + ' -L' + libcxx_libs_path
libstdcxx_libs = '-lc++_static -lc++abi' libstdcxx_libs = '-lc++_static -lc++abi'
if self.is_armv7:
# On 32 bit ARM, clang generates no ".eh_frame" section;
# instead, the LLVM unwinder library is used for unwinding
# the stack after a C++ exception was thrown
libstdcxx_libs += ' -lunwind'
if use_cxx: if use_cxx:
self.cxxflags += ' ' + libstdcxx_cxxflags self.cxxflags += ' ' + libstdcxx_cxxflags
self.ldflags += ' ' + libstdcxx_ldflags self.ldflags += ' ' + libstdcxx_ldflags

View File

@@ -6,7 +6,7 @@ android_sdk = get_option('android_sdk')
android_abi = get_option('android_abi') android_abi = get_option('android_abi')
android_sdk_build_tools_version = '27.0.0' android_sdk_build_tools_version = '27.0.0'
android_sdk_platform = 'android-21' android_sdk_platform = 'android-23'
android_build_tools_dir = join_paths(android_sdk, 'build-tools', android_sdk_build_tools_version) 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_sdk_platform_dir = join_paths(android_sdk, 'platforms', android_sdk_platform)

View File

@@ -21,10 +21,12 @@ package org.musicpd;
import java.util.LinkedList; import java.util.LinkedList;
import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
@@ -178,6 +180,14 @@ public class Settings extends Activity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { 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); setContentView(R.layout.settings);
mRunButton = (ToggleButton) findViewById(R.id.run); mRunButton = (ToggleButton) findViewById(R.id.run);
mRunButton.setOnCheckedChangeListener(mOnRunChangeListener); mRunButton.setOnCheckedChangeListener(mOnRunChangeListener);
@@ -203,6 +213,31 @@ public class Settings extends Activity {
super.onCreate(savedInstanceState); 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() { private void connectClient() {
mClient = new Main.Client(this, new Main.Client.Callback() { mClient = new Main.Client(this, new Main.Client.Callback() {

View File

@@ -38,7 +38,7 @@ author = 'Max Kellermann'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.21.7' version = '0.21.10'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = version release = version

View File

@@ -2,12 +2,12 @@ Developer's Manual
################## ##################
Introduction Introduction
============ ************
This is a guide for those who wish to hack on the MPD source code. MPD is an open project, and we are always happy about contributions. So far, more than 150 people have contributed patches. This document is work in progress. Most of it may be incomplete yet. Please help! This is a guide for those who wish to hack on the MPD source code. MPD is an open project, and we are always happy about contributions. So far, more than 150 people have contributed patches. This document is work in progress. Most of it may be incomplete yet. Please help!
Code Style Code Style
========== **********
* indent with tabs (width 8) * indent with tabs (width 8)
* don't write CPP when you can write C++: use inline functions and constexpr instead of macros * don't write CPP when you can write C++: use inline functions and constexpr instead of macros
@@ -18,7 +18,6 @@ Code Style
* classes and functions names use CamelCase; variables are lower-case with words separated by underscore * classes and functions names use CamelCase; variables are lower-case with words separated by underscore
Some example code: Some example code:
~~~~~~~~~~~~~~~~~~
.. code-block:: c .. code-block:: c
@@ -33,7 +32,7 @@ Some example code:
} }
Hacking The Source Hacking The Source
================== ******************
MPD sources are managed in a git repository on MPD sources are managed in a git repository on
`Github <https://github.com/MusicPlayerDaemon/>`_. `Github <https://github.com/MusicPlayerDaemon/>`_.
@@ -59,7 +58,7 @@ possible, to be sure that you don't break any disabled code.
Don't mix several changes in one single patch. Create a separate patch for every change. Tools like :program:`stgit` help you with that. This way, we can review your patches more easily, and we can pick the patches we like most first. Don't mix several changes in one single patch. Create a separate patch for every change. Tools like :program:`stgit` help you with that. This way, we can review your patches more easily, and we can pick the patches we like most first.
Basic stgit usage Basic stgit usage
----------------- =================
stgit allows you to create a set of patches and refine all of them: you can go back to any patch at any time, and re-edit it (both the code and the commit message). You can reorder patches and insert new patches at any position. It encourages creating separate patches for tiny changes. stgit allows you to create a set of patches and refine all of them: you can go back to any patch at any time, and re-edit it (both the code and the commit message). You can reorder patches and insert new patches at any position. It encourages creating separate patches for tiny changes.
@@ -94,35 +93,7 @@ When the whole patch series is finished, convert stgit patches to git commits:
stg commit stg commit
Submitting Patches Submitting Patches
================== ******************
Send your patches to the mailing list: Submit pull requests on GitHub:
Email: `mpd-devel <mpd-devel@musicpd.org>`_ https://github.com/MusicPlayerDaemon/MPD/pulls
:program:`git pull` requests are preferred.
Development Tools
=================
Clang Static Analyzer
---------------------
The `static analyzer <http://clang-analyzer.llvm.org/>`_ is a tool that helps find bugs. To run it on the MPD code base, install LLVM and clang. configure MPD to use clang:
.. code-block:: sh
./configure --enable-debug CXX=clang++ CC=clang ...
It is recommended to use :code:`--enable-debug`, because the analyzer
takes advantage of :dfn:`assert()` calls, which are only enabled in
the debug build.
Now run the analyzer:
.. code-block:: sh
scan-build --use-c++=clang++ --use-cc=clang make
The options :code:`--use-c++` and :code:`--use-cc` are necessary
because it invokes :command:`cc` for actually compiling the sources by
default. That breaks, because MPD requires a C99 compiler.

View File

@@ -140,7 +140,6 @@ of database.
.B auto_update_depth <N> .B auto_update_depth <N>
Limit the depth of the directories being watched, 0 means only watch Limit the depth of the directories being watched, 0 means only watch
the music directory itself. There is no limit by default. the music directory itself. There is no limit by default.
.TP
.SH REQUIRED AUDIO OUTPUT PARAMETERS .SH REQUIRED AUDIO OUTPUT PARAMETERS
.TP .TP
.B type <type> .B type <type>
@@ -164,57 +163,12 @@ Specifies how replay gain is applied. The default is "software",
which uses an internal software volume control. "mixer" uses the which uses an internal software volume control. "mixer" uses the
configured (hardware) mixer control. "none" disables replay gain on configured (hardware) mixer control. "none" disables replay gain on
this audio output. this audio output.
.SH OPTIONAL ALSA OUTPUT PARAMETERS
.TP
.B device <dev>
This specifies the device to use for audio output. The default is "default".
.TP .TP
.B mixer_type <hardware, software or none> .B mixer_type <hardware, software or none>
Specifies which mixer should be used for this audio output: the Specifies which mixer should be used for this audio output: the
hardware mixer (available for ALSA, OSS and PulseAudio), the software hardware mixer (available for ALSA, OSS and PulseAudio), the software
mixer or no mixer ("none"). By default, the hardware mixer is used mixer or no mixer ("none"). By default, the hardware mixer is used
for devices which support it, and none for the others. for devices which support it, and none for the others.
.TP
.B mixer_device <mixer dev>
This specifies which mixer to use. The default is "default". To use
the second sound card in a system, use "hw:1".
.TP
.B mixer_control <mixer ctrl>
This specifies which mixer control to use (sometimes referred to as
the "device"). The default is "PCM". Use "amixer scontrols" to see
the list of possible controls.
.TP
.B mixer_index <mixer index>
A number identifying the index of the named mixer control. This is
probably only useful if your alsa device has more than one
identically\-named mixer control. The default is "0". Use "amixer
scontrols" to see the list of controls with their indexes.
.TP
.B auto_resample <yes or no>
Setting this to "no" disables ALSA's software resampling, if the
hardware does not support a specific sample rate. This lets MPD do
the resampling. "yes" is the default and allows ALSA to resample.
.TP
.B auto_channels <yes or no>
Setting this to "no" disables ALSA's channel conversion, if the
hardware does not support a specific number of channels. Default: "yes".
.TP
.B auto_format <yes or no>
Setting this to "no" disables ALSA's sample format conversion, if the
hardware does not support a specific sample format. Default: "yes".
.TP
.B buffer_time <time in microseconds>
This sets the length of the hardware sample buffer in microseconds. Increasing
it may help to reduce or eliminate skipping on certain setups. Most users do
not need to change this. The default is 500000 microseconds (0.5 seconds).
.TP
.B period_time <time in microseconds>
This sets the time between hardware sample transfers in microseconds.
Increasing this can reduce CPU usage while lowering it can reduce underrun
errors on bandwidth-limited devices. Some users have reported good results
with this set to 50000, but not all devices support values this high. Most
users do not need to change this. The default is 256000000 / sample_rate(kHz),
or 5804 microseconds for CD-quality audio.
.SH FILES .SH FILES
.TP .TP
.BI ~/.mpdconf .BI ~/.mpdconf

View File

@@ -4,10 +4,10 @@ Plugin reference
.. _database_plugins: .. _database_plugins:
Database plugins Database plugins
---------------- ================
simple simple
~~~~~~ ------
The default plugin. Stores a copy of the database in memory. A file is used for permanent storage. The default plugin. Stores a copy of the database in memory. A file is used for permanent storage.
@@ -25,7 +25,7 @@ The default plugin. Stores a copy of the database in memory. A file is used for
- Compress the database file using gzip? Enabled by default (if built with zlib). - Compress the database file using gzip? Enabled by default (if built with zlib).
proxy proxy
~~~~~ -----
Provides access to the database of another :program:`MPD` instance using libmpdclient. This is useful when you run mount the music directory via NFS/SMB, and the file server already runs a :program:`MPD` instance. Only the file server needs to update the database. Provides access to the database of another :program:`MPD` instance using libmpdclient. This is useful when you run mount the music directory via NFS/SMB, and the file server already runs a :program:`MPD` instance. Only the file server needs to update the database.
@@ -45,30 +45,30 @@ Provides access to the database of another :program:`MPD` instance using libmpdc
- Send TCP keepalive packets to the "master" :program:`MPD` instance? This option can help avoid certain firewalls dropping inactive connections, at the expensive of a very small amount of additional network traffic. Disabled by default. - Send TCP keepalive packets to the "master" :program:`MPD` instance? This option can help avoid certain firewalls dropping inactive connections, at the expensive of a very small amount of additional network traffic. Disabled by default.
upnp upnp
~~~~ ----
Provides access to UPnP media servers. Provides access to UPnP media servers.
Storage plugins Storage plugins
--------------- ===============
local local
~~~~~ -----
The default plugin which gives :program:`MPD` access to local files. It is used when music_directory refers to a local directory. The default plugin which gives :program:`MPD` access to local files. It is used when music_directory refers to a local directory.
curl curl
~~~~ ----
A WebDAV client using libcurl. It is used when :code:`music_directory` contains a http:// or https:// URI, for example :samp:`https://the.server/dav/`. A WebDAV client using libcurl. It is used when :code:`music_directory` contains a http:// or https:// URI, for example :samp:`https://the.server/dav/`.
smbclient smbclient
~~~~~~~~~ ---------
Load music files from a SMB/CIFS server. It is used when :code:`music_directory` contains a smb:// URI, for example :samp:`smb://myfileserver/Music`. Load music files from a SMB/CIFS server. It is used when :code:`music_directory` contains a smb:// URI, for example :samp:`smb://myfileserver/Music`.
nfs nfs
~~~ ---
Load music files from a NFS server. It is used when :code:`music_directory` contains a nfs:// URI according to RFC2224, for example :samp:`nfs://servername/path`. Load music files from a NFS server. It is used when :code:`music_directory` contains a nfs:// URI according to RFC2224, for example :samp:`nfs://servername/path`.
@@ -81,7 +81,7 @@ This plugin uses libnfs, which supports only NFS version 3. Since :program:`MPD`
Don't fear: "insecure" does not mean that your NFS server is insecure. A few decades ago, people thought the concept of "privileged ports" would make network services "secure", which was a fallacy. The absence of this obsolete "security" measure means little. Don't fear: "insecure" does not mean that your NFS server is insecure. A few decades ago, people thought the concept of "privileged ports" would make network services "secure", which was a fallacy. The absence of this obsolete "security" measure means little.
udisks udisks
~~~~~~ ------
Mount file systems (e.g. USB sticks or other removable media) using Mount file systems (e.g. USB sticks or other removable media) using
the udisks2 daemon via D-Bus. To obtain a valid udisks2 URI, consult the udisks2 daemon via D-Bus. To obtain a valid udisks2 URI, consult
@@ -106,29 +106,30 @@ MPD user.
.. _neighbor_plugin: .. _neighbor_plugin:
Neighbor plugins Neighbor plugins
---------------- ================
smbclient smbclient
~~~~~~~~~ ---------
Provides a list of SMB/CIFS servers on the local network. Provides a list of SMB/CIFS servers on the local network.
udisks udisks
~~~~~~ ------
Queries the udisks2 daemon via D-Bus and obtain a list of file systems (e.g. USB sticks or other removable media). Queries the udisks2 daemon via D-Bus and obtain a list of file systems (e.g. USB sticks or other removable media).
upnp upnp
~~~~ ----
Provides a list of UPnP servers on the local network. Provides a list of UPnP servers on the local network.
.. _input_plugins: .. _input_plugins:
Input plugins Input plugins
------------- =============
alsa alsa
~~~~ ----
Allows :program:`MPD` on Linux to play audio directly from a soundcard using the scheme alsa://. Audio is formatted as 44.1 kHz 16-bit stereo (CD format). Examples: Allows :program:`MPD` on Linux to play audio directly from a soundcard using the scheme alsa://. Audio is formatted as 44.1 kHz 16-bit stereo (CD format). Examples:
@@ -141,7 +142,7 @@ Allows :program:`MPD` on Linux to play audio directly from a soundcard using the
mpc add alsa://hw:1,0 plays audio from device hw:1,0 cdio_paranoia mpc add alsa://hw:1,0 plays audio from device hw:1,0 cdio_paranoia
cdio_paranoia cdio_paranoia
~~~~~~~~~~~~~ -------------
Plays audio CDs using libcdio. The URI has the form: "cdda://[DEVICE][/TRACK]". The simplest form cdda:// plays the whole disc in the default drive. Plays audio CDs using libcdio. The URI has the form: "cdda://[DEVICE][/TRACK]". The simplest form cdda:// plays the whole disc in the default drive.
@@ -157,7 +158,7 @@ Plays audio CDs using libcdio. The URI has the form: "cdda://[DEVICE][/TRACK]".
- Request CDParanoia cap the extraction speed to Nx normal CD audio rotation speed, keeping the drive quiet. - Request CDParanoia cap the extraction speed to Nx normal CD audio rotation speed, keeping the drive quiet.
curl curl
~~~~ ----
Opens remote files or streams over HTTP using libcurl. Opens remote files or streams over HTTP using libcurl.
@@ -179,22 +180,22 @@ Note that unless overridden by the below settings (e.g. by setting them to a bla
- Verify the certificate's name against host? `More information <http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html>`_. - Verify the certificate's name against host? `More information <http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html>`_.
ffmpeg ffmpeg
~~~~~~ ------
Access to various network protocols implemented by the FFmpeg library: gopher://, rtp://, rtsp://, rtmp://, rtmpt://, rtmps:// Access to various network protocols implemented by the FFmpeg library: gopher://, rtp://, rtsp://, rtmp://, rtmpt://, rtmps://
file file
~~~~ ----
Opens local files Opens local files
mms mms
~~~ ---
Plays streams with the MMS protocol using `libmms <https://launchpad.net/libmms>`_. Plays streams with the MMS protocol using `libmms <https://launchpad.net/libmms>`_.
nfs nfs
~~~ ---
Allows :program:`MPD` to access files on NFSv3 servers without actually mounting them (i.e. in userspace, without help from the kernel's VFS layer). All URIs with the nfs:// scheme are used according to RFC2224. Example: Allows :program:`MPD` to access files on NFSv3 servers without actually mounting them (i.e. in userspace, without help from the kernel's VFS layer). All URIs with the nfs:// scheme are used according to RFC2224. Example:
@@ -205,7 +206,7 @@ Allows :program:`MPD` to access files on NFSv3 servers without actually mounting
Note that this usually requires enabling the "insecure" flag in the server's /etc/exports file, because :program:`MPD` cannot bind to so-called "privileged" ports. Don't fear: this will not make your file server insecure; the flag was named in a time long ago when privileged ports were thought to be meaningful for security. By today's standards, NFSv3 is not secure at all, and if you believe it is, you're already doomed. Note that this usually requires enabling the "insecure" flag in the server's /etc/exports file, because :program:`MPD` cannot bind to so-called "privileged" ports. Don't fear: this will not make your file server insecure; the flag was named in a time long ago when privileged ports were thought to be meaningful for security. By today's standards, NFSv3 is not secure at all, and if you believe it is, you're already doomed.
smbclient smbclient
~~~~~~~~~ ---------
Allows :program:`MPD` to access files on SMB/CIFS servers (e.g. Samba or Microsoft Windows). All URIs with the smb:// scheme are used. Example: Allows :program:`MPD` to access files on SMB/CIFS servers (e.g. Samba or Microsoft Windows). All URIs with the smb:// scheme are used. Example:
@@ -214,7 +215,7 @@ Allows :program:`MPD` to access files on SMB/CIFS servers (e.g. Samba or Microso
mpc add smb://servername/sharename/filename.ogg mpc add smb://servername/sharename/filename.ogg
qobuz qobuz
~~~~~ -----
Play songs from the commercial streaming service Qobuz. It plays URLs in the form qobuz://track/ID, e.g.: Play songs from the commercial streaming service Qobuz. It plays URLs in the form qobuz://track/ID, e.g.:
@@ -240,7 +241,7 @@ Play songs from the commercial streaming service Qobuz. It plays URLs in the for
- The `Qobuz format identifier <https://github.com/Qobuz/api-documentation/blob/master/endpoints/track/getFileUrl.md#parameters>`_, i.e. a number which chooses the format and quality to be requested from Qobuz. The default is "5" (320 kbit/s MP3). - The `Qobuz format identifier <https://github.com/Qobuz/api-documentation/blob/master/endpoints/track/getFileUrl.md#parameters>`_, i.e. a number which chooses the format and quality to be requested from Qobuz. The default is "5" (320 kbit/s MP3).
tidal tidal
~~~~~ -----
Play songs from the commercial streaming service `Tidal <http://tidal.com/>`_. It plays URLs in the form tidal://track/ID, e.g.: Play songs from the commercial streaming service `Tidal <http://tidal.com/>`_. It plays URLs in the form tidal://track/ID, e.g.:
@@ -266,10 +267,10 @@ Play songs from the commercial streaming service `Tidal <http://tidal.com/>`_. I
.. _decoder_plugins: .. _decoder_plugins:
Decoder plugins Decoder plugins
--------------- ===============
adplug adplug
~~~~~~ ------
Decodes AdLib files using libadplug. Decodes AdLib files using libadplug.
@@ -283,17 +284,17 @@ Decodes AdLib files using libadplug.
- The sample rate that shall be synthesized by the plugin. Defaults to 48000. - The sample rate that shall be synthesized by the plugin. Defaults to 48000.
audiofile audiofile
~~~~~~~~~ ---------
Decodes WAV and AIFF files using libaudiofile. Decodes WAV and AIFF files using libaudiofile.
faad faad
~~~~ ----
Decodes AAC files using libfaad. Decodes AAC files using libfaad.
ffmpeg ffmpeg
~~~~~~ ------
Decodes various codecs using FFmpeg. Decodes various codecs using FFmpeg.
@@ -309,12 +310,12 @@ Decodes various codecs using FFmpeg.
- Sets the FFmpeg muxer option probesize, which specifies probing size in bytes, i.e. the size of the data to analyze to get stream information. The `FFmpeg formats documentation <https://ffmpeg.org/ffmpeg-formats.html>`_ has more information. - Sets the FFmpeg muxer option probesize, which specifies probing size in bytes, i.e. the size of the data to analyze to get stream information. The `FFmpeg formats documentation <https://ffmpeg.org/ffmpeg-formats.html>`_ has more information.
flac flac
~~~~ ----
Decodes FLAC files using libFLAC. Decodes FLAC files using libFLAC.
dsdiff dsdiff
~~~~~~ ------
Decodes DFF files containing DSDIFF data (e.g. SACD rips). Decodes DFF files containing DSDIFF data (e.g. SACD rips).
@@ -328,12 +329,12 @@ Decodes DFF files containing DSDIFF data (e.g. SACD rips).
- Decode the least significant bit first. Default is no. - Decode the least significant bit first. Default is no.
dsf dsf
~~~ ---
Decodes DSF files containing DSDIFF data (e.g. SACD rips). Decodes DSF files containing DSDIFF data (e.g. SACD rips).
fluidsynth fluidsynth
~~~~~~~~~~ ----------
MIDI decoder based on `FluidSynth <http://www.fluidsynth.org/>`_. MIDI decoder based on `FluidSynth <http://www.fluidsynth.org/>`_.
@@ -349,7 +350,7 @@ MIDI decoder based on `FluidSynth <http://www.fluidsynth.org/>`_.
- The absolute path of the soundfont file. Defaults to :file:`/usr/share/sounds/sf2/FluidR3_GM.sf2`. - The absolute path of the soundfont file. Defaults to :file:`/usr/share/sounds/sf2/FluidR3_GM.sf2`.
gme gme
~~~ ---
Video game music file emulator based on `game-music-emu <https://bitbucket.org/mpyne/game-music-emu/wiki/Home>`_. Video game music file emulator based on `game-music-emu <https://bitbucket.org/mpyne/game-music-emu/wiki/Home>`_.
@@ -363,7 +364,7 @@ Video game music file emulator based on `game-music-emu <https://bitbucket.org/m
- Enable more accurate sound emulation. - Enable more accurate sound emulation.
hybrid_dsd hybrid_dsd
~~~~~~~~~~ ----------
`Hybrid-DSD `Hybrid-DSD
<http://dsdmaster.blogspot.de/p/bitperfect-introduces-hybrid-dsd-file.html>`_ <http://dsdmaster.blogspot.de/p/bitperfect-introduces-hybrid-dsd-file.html>`_
@@ -386,12 +387,12 @@ of the file is better.
- This specifies whether to support gapless playback of MP3s which have the necessary headers. Useful if your MP3s have headers with incorrect information. If you have such MP3s, it is highly recommended that you fix them using `vbrfix <http://www.willwap.co.uk/Programs/vbrfix.php>`_ instead of disabling gapless MP3 playback. The default is to support gapless MP3 playback. - This specifies whether to support gapless playback of MP3s which have the necessary headers. Useful if your MP3s have headers with incorrect information. If you have such MP3s, it is highly recommended that you fix them using `vbrfix <http://www.willwap.co.uk/Programs/vbrfix.php>`_ instead of disabling gapless MP3 playback. The default is to support gapless MP3 playback.
mad mad
~~~ ---
Decodes MP3 files using `libmad <http://www.underbit.com/products/mad/>`_. Decodes MP3 files using `libmad <http://www.underbit.com/products/mad/>`_.
mikmod mikmod
~~~~~~ ------
Module player based on `MikMod <http://mikmod.sourceforge.net/>`_. Module player based on `MikMod <http://mikmod.sourceforge.net/>`_.
@@ -407,7 +408,7 @@ Module player based on `MikMod <http://mikmod.sourceforge.net/>`_.
- Sets the sample rate generated by libmikmod. Default is 44100. - Sets the sample rate generated by libmikmod. Default is 44100.
modplug modplug
~~~~~~~ -------
Module player based on MODPlug. Module player based on MODPlug.
@@ -421,27 +422,27 @@ Module player based on MODPlug.
- Number of times to loop the module if it uses backward loops. Default is 0 which prevents looping. -1 loops forever. - Number of times to loop the module if it uses backward loops. Default is 0 which prevents looping. -1 loops forever.
mpcdec mpcdec
~~~~~~ ------
Decodes Musepack files using `libmpcdec <http://www.musepack.net/>`_. Decodes Musepack files using `libmpcdec <http://www.musepack.net/>`_.
mpg123 mpg123
~~~~~~ ------
Decodes MP3 files using `libmpg123 <http://www.mpg123.de/>`_. Decodes MP3 files using `libmpg123 <http://www.mpg123.de/>`_.
opus opus
~~~~ ----
Decodes Opus files using `libopus <http://www.opus-codec.org/>`_. Decodes Opus files using `libopus <http://www.opus-codec.org/>`_.
pcm pcm
~~~ ---
Read raw PCM samples. It understands the "audio/L16" MIME type with parameters "rate" and "channels" according to RFC 2586. It also understands the MPD-specific MIME type "audio/x-mpd-float". Read raw PCM samples. It understands the "audio/L16" MIME type with parameters "rate" and "channels" according to RFC 2586. It also understands the MPD-specific MIME type "audio/x-mpd-float".
sidplay sidplay
~~~~~~~ -------
C64 SID decoder based on `libsidplayfp <https://sourceforge.net/projects/sidplay-residfp/>`_ or `libsidplay2 <https://sourceforge.net/projects/sidplay2/>`_. C64 SID decoder based on `libsidplayfp <https://sourceforge.net/projects/sidplay-residfp/>`_ or `libsidplay2 <https://sourceforge.net/projects/sidplay2/>`_.
@@ -463,23 +464,23 @@ C64 SID decoder based on `libsidplayfp <https://sourceforge.net/projects/sidplay
- Only libsidplayfp. Absolute path to basic rom image file. - Only libsidplayfp. Absolute path to basic rom image file.
sndfile sndfile
~~~~~~~ -------
Decodes WAV and AIFF files using `libsndfile <http://www.mega-nerd.com/libsndfile/>`_. Decodes WAV and AIFF files using `libsndfile <http://www.mega-nerd.com/libsndfile/>`_.
vorbis vorbis
~~~~~~ ------
Decodes Ogg-Vorbis files using `libvorbis <http://www.xiph.org/ogg/vorbis/>`_. Decodes Ogg-Vorbis files using `libvorbis <http://www.xiph.org/ogg/vorbis/>`_.
wavpack wavpack
~~~~~~~ -------
Decodes WavPack files using `libwavpack <http://www.wavpack.com/>`_. Decodes WavPack files using `libwavpack <http://www.wavpack.com/>`_.
wildmidi wildmidi
~~~~~~~~ --------
MIDI decoder based on `libwildmidi <http://www.mindwerks.net/projects/wildmidi/>`_. MIDI decoder based on `libwildmidi <http://www.mindwerks.net/projects/wildmidi/>`_.
@@ -495,10 +496,11 @@ MIDI decoder based on `libwildmidi <http://www.mindwerks.net/projects/wildmidi/>
.. _encoder_plugins: .. _encoder_plugins:
Encoder plugins Encoder plugins
--------------- ===============
flac flac
~~~~ ----
Encodes into `FLAC <https://xiph.org/flac/>`_ (lossless). Encodes into `FLAC <https://xiph.org/flac/>`_ (lossless).
.. list-table:: .. list-table::
@@ -511,7 +513,7 @@ Encodes into `FLAC <https://xiph.org/flac/>`_ (lossless).
- Sets the libFLAC compression level. The levels range from 0 (fastest, least compression) to 8 (slowest, most compression). - Sets the libFLAC compression level. The levels range from 0 (fastest, least compression) to 8 (slowest, most compression).
lame lame
~~~~ ----
Encodes into MP3 using the `LAME <http://lame.sourceforge.net/>`_ library. Encodes into MP3 using the `LAME <http://lame.sourceforge.net/>`_ library.
@@ -527,12 +529,12 @@ Encodes into MP3 using the `LAME <http://lame.sourceforge.net/>`_ library.
- Sets the bit rate in kilobit per second. Cannot be used with quality. - Sets the bit rate in kilobit per second. Cannot be used with quality.
null null
~~~~ ----
Does not encode anything, passes the input PCM data as-is. Does not encode anything, passes the input PCM data as-is.
shine shine
~~~~~ -----
Encodes into MP3 using the `Shine <https://github.com/savonet/shine>`_ library. Encodes into MP3 using the `Shine <https://github.com/savonet/shine>`_ library.
@@ -546,7 +548,7 @@ Encodes into MP3 using the `Shine <https://github.com/savonet/shine>`_ library.
- Sets the bit rate in kilobit per second. - Sets the bit rate in kilobit per second.
twolame twolame
~~~~~~~ -------
Encodes into MP2 using the `TwoLAME <http://www.twolame.org/>`_ library. Encodes into MP2 using the `TwoLAME <http://www.twolame.org/>`_ library.
@@ -562,7 +564,7 @@ Encodes into MP2 using the `TwoLAME <http://www.twolame.org/>`_ library.
- Sets the bit rate in kilobit per second. Cannot be used with quality. - Sets the bit rate in kilobit per second. Cannot be used with quality.
opus opus
~~~~ ----
Encodes into `Ogg Opus <http://www.opus-codec.org/>`_. Encodes into `Ogg Opus <http://www.opus-codec.org/>`_.
@@ -584,7 +586,7 @@ Encodes into `Ogg Opus <http://www.opus-codec.org/>`_.
.. _vorbis_plugin: .. _vorbis_plugin:
vorbis vorbis
~~~~~~ ------
Encodes into `Ogg Vorbis <http://www.vorbis.com/>`_. Encodes into `Ogg Vorbis <http://www.vorbis.com/>`_.
@@ -600,13 +602,13 @@ Encodes into `Ogg Vorbis <http://www.vorbis.com/>`_.
- Sets the bit rate in kilobit per second. Cannot be used with quality. - Sets the bit rate in kilobit per second. Cannot be used with quality.
wave wave
~~~~ ----
Encodes into WAV (lossless). Encodes into WAV (lossless).
.. _resampler_plugins: .. _resampler_plugins:
Resampler plugins Resampler plugins
----------------- =================
The resampler can be configured in a block named resampler, for example: The resampler can be configured in a block named resampler, for example:
@@ -629,12 +631,12 @@ The following table lists the resampler options valid for all plugins:
- The name of the plugin. - The name of the plugin.
internal internal
~~~~~~~~ --------
A resampler built into :program:`MPD`. Its quality is very poor, but its CPU usage is low. This is the fallback if :program:`MPD` was compiled without an external resampler. A resampler built into :program:`MPD`. Its quality is very poor, but its CPU usage is low. This is the fallback if :program:`MPD` was compiled without an external resampler.
libsamplerate libsamplerate
~~~~~~~~~~~~~ -------------
A resampler using `libsamplerate <http://www.mega-nerd.com/SRC/>`_ a.k.a. Secret Rabbit Code (SRC). A resampler using `libsamplerate <http://www.mega-nerd.com/SRC/>`_ a.k.a. Secret Rabbit Code (SRC).
@@ -667,7 +669,7 @@ The following converter types are provided by libsamplerate:
- Linear interpolator, very fast, poor quality. - Linear interpolator, very fast, poor quality.
soxr soxr
~~~~ ----
A resampler using `libsoxr <http://sourceforge.net/projects/soxr/>`_, the SoX Resampler library A resampler using `libsoxr <http://sourceforge.net/projects/soxr/>`_, the SoX Resampler library
@@ -693,12 +695,12 @@ Valid quality values for libsoxr:
.. _output_plugins: .. _output_plugins:
Output plugins Output plugins
-------------- ==============
.. _alsa_plugin: .. _alsa_plugin:
alsa alsa
~~~~ ----
The `Advanced Linux Sound Architecture (ALSA) <http://www.alsa-project.org/>`_ plugin uses libasound. It is recommended if you are using Linux. The `Advanced Linux Sound Architecture (ALSA) <http://www.alsa-project.org/>`_ plugin uses libasound. It is recommended if you are using Linux.
@@ -757,7 +759,7 @@ The following attributes can be configured at runtime using the outputset comman
ao ao
~~ --
The ao plugin uses the portable `libao <https://www.xiph.org/ao/>`_ library. Use only if there is no native plugin for your operating system. The ao plugin uses the portable `libao <https://www.xiph.org/ao/>`_ library. Use only if there is no native plugin for your operating system.
.. list-table:: .. list-table::
@@ -774,7 +776,8 @@ The ao plugin uses the portable `libao <https://www.xiph.org/ao/>`_ library. Use
- This specifies how many bytes to write to the audio device at once. This parameter is to work around a bug in older versions of libao on sound cards with very small buffers. The default is 1024. - This specifies how many bytes to write to the audio device at once. This parameter is to work around a bug in older versions of libao on sound cards with very small buffers. The default is 1024.
sndio sndio
~~~~~ -----
The sndio plugin uses the `sndio <http://www.sndio.org/>`_ library. It should normally be used on OpenBSD. The sndio plugin uses the `sndio <http://www.sndio.org/>`_ library. It should normally be used on OpenBSD.
.. list-table:: .. list-table::
@@ -789,7 +792,7 @@ The sndio plugin uses the `sndio <http://www.sndio.org/>`_ library. It should no
- Set the application buffer time in milliseconds. - Set the application buffer time in milliseconds.
fifo fifo
~~~~ ----
The fifo plugin writes raw PCM data to a FIFO (First In, First Out) file. The data can be read by another program. The fifo plugin writes raw PCM data to a FIFO (First In, First Out) file. The data can be read by another program.
@@ -803,7 +806,7 @@ The fifo plugin writes raw PCM data to a FIFO (First In, First Out) file. The da
- This specifies the path of the FIFO to write to. Must be an absolute path. If the path does not exist, it will be created when MPD is started, and removed when MPD is stopped. The FIFO will be created with the same user and group as MPD is running as. Default permissions can be modified by using the builtin shell command umask. If a FIFO already exists at the specified path it will be reused, and will not be removed when MPD is stopped. You can use the "mkfifo" command to create this, and then you may modify the permissions to your liking. - This specifies the path of the FIFO to write to. Must be an absolute path. If the path does not exist, it will be created when MPD is started, and removed when MPD is stopped. The FIFO will be created with the same user and group as MPD is running as. Default permissions can be modified by using the builtin shell command umask. If a FIFO already exists at the specified path it will be reused, and will not be removed when MPD is stopped. You can use the "mkfifo" command to create this, and then you may modify the permissions to your liking.
haiku haiku
~~~~~ -----
Use the SoundPlayer API on the Haiku operating system. Use the SoundPlayer API on the Haiku operating system.
@@ -812,7 +815,8 @@ removed soon, unless there is a new maintainer.
jack jack
~~~~ ----
The jack plugin connects to a `JACK server <http://jackaudio.org/>`_. The jack plugin connects to a `JACK server <http://jackaudio.org/>`_.
.. list-table:: .. list-table::
@@ -835,7 +839,8 @@ The jack plugin connects to a `JACK server <http://jackaudio.org/>`_.
- Sets the size of the ring buffer for each channel. Do not configure this value unless you know what you're doing. - Sets the size of the ring buffer for each channel. Do not configure this value unless you know what you're doing.
httpd httpd
~~~~~ -----
The httpd plugin creates a HTTP server, similar to `ShoutCast <http://www.shoutcast.com/>`_ / `IceCast <http://icecast.org/>`_. HTTP streaming clients like mplayer, VLC, and mpv can connect to it. The httpd plugin creates a HTTP server, similar to `ShoutCast <http://www.shoutcast.com/>`_ / `IceCast <http://icecast.org/>`_. HTTP streaming clients like mplayer, VLC, and mpv can connect to it.
It is highly recommended to configure a fixed format, because a stream cannot switch its audio format on-the-fly when the song changes. It is highly recommended to configure a fixed format, because a stream cannot switch its audio format on-the-fly when the song changes.
@@ -856,7 +861,8 @@ It is highly recommended to configure a fixed format, because a stream cannot sw
- Sets a limit, number of concurrent clients. When set to 0 no limit will apply. - Sets a limit, number of concurrent clients. When set to 0 no limit will apply.
null null
~~~~ ----
The null plugin does nothing. It discards everything sent to it. The null plugin does nothing. It discards everything sent to it.
.. list-table:: .. list-table::
@@ -871,7 +877,8 @@ The null plugin does nothing. It discards everything sent to it.
.. _oss_plugin: .. _oss_plugin:
oss oss
~~~ ---
The "Open Sound System" plugin is supported on most Unix platforms. The "Open Sound System" plugin is supported on most Unix platforms.
On Linux, OSS has been superseded by ALSA. Use the ALSA output plugin :ref:`alsa_plugin` instead of this one on Linux. On Linux, OSS has been superseded by ALSA. Use the ALSA output plugin :ref:`alsa_plugin` instead of this one on Linux.
@@ -899,7 +906,7 @@ The according hardware mixer plugin understands the following settings:
- Choose a mixer control, defaulting to PCM. - Choose a mixer control, defaulting to PCM.
openal openal
~~~~~~ ------
The "OpenAL" plugin uses `libopenal <http://kcat.strangesoft.net/openal.html>`_. It is supported on many platforms. Use only if there is no native plugin for your operating system. The "OpenAL" plugin uses `libopenal <http://kcat.strangesoft.net/openal.html>`_. It is supported on many platforms. Use only if there is no native plugin for your operating system.
.. list-table:: .. list-table::
@@ -912,7 +919,7 @@ The "OpenAL" plugin uses `libopenal <http://kcat.strangesoft.net/openal.html>`_.
- Sets the device which should be used. This can be any valid OpenAL device name. If not specified, then libopenal will choose a default device. - Sets the device which should be used. This can be any valid OpenAL device name. If not specified, then libopenal will choose a default device.
osx osx
~~~ ---
The "Mac OS X" plugin uses Apple's CoreAudio API. The "Mac OS X" plugin uses Apple's CoreAudio API.
.. list-table:: .. list-table::
@@ -933,7 +940,7 @@ The "Mac OS X" plugin uses Apple's CoreAudio API.
The channel map may not refer to outputs that do not exist according to the format. If the format is "*:*:1" (mono) and you have a four-channel sound card then "-1,-1,0,0" (dual mono output on the second pair of sound card outputs) is a valid channel map but "-1,-1,0,1" is not because the second channel ('1') does not exist when the output is mono. The channel map may not refer to outputs that do not exist according to the format. If the format is "*:*:1" (mono) and you have a four-channel sound card then "-1,-1,0,0" (dual mono output on the second pair of sound card outputs) is a valid channel map but "-1,-1,0,1" is not because the second channel ('1') does not exist when the output is mono.
pipe pipe
~~~~ ----
The pipe plugin starts a program and writes raw PCM data into its standard input. The pipe plugin starts a program and writes raw PCM data into its standard input.
@@ -949,7 +956,7 @@ The pipe plugin starts a program and writes raw PCM data into its standard input
.. _pulse_plugin: .. _pulse_plugin:
pulse pulse
~~~~~ -----
The pulse plugin connects to a `PulseAudio <http://www.freedesktop.org/wiki/Software/PulseAudio/>`_ server. Requires libpulse. The pulse plugin connects to a `PulseAudio <http://www.freedesktop.org/wiki/Software/PulseAudio/>`_ server. Requires libpulse.
.. list-table:: .. list-table::
@@ -966,7 +973,7 @@ The pulse plugin connects to a `PulseAudio <http://www.freedesktop.org/wiki/Soft
- Specifies a linear scaling coefficient (ranging from 0.5 to 5.0) to apply when adjusting volume through :program:`MPD`. For example, chosing a factor equal to ``"0.7"`` means that setting the volume to 100 in :program:`MPD` will set the PulseAudio volume to 70%, and a factor equal to ``"3.5"`` means that volume 100 in :program:`MPD` corresponds to a 350% PulseAudio volume. - Specifies a linear scaling coefficient (ranging from 0.5 to 5.0) to apply when adjusting volume through :program:`MPD`. For example, chosing a factor equal to ``"0.7"`` means that setting the volume to 100 in :program:`MPD` will set the PulseAudio volume to 70%, and a factor equal to ``"3.5"`` means that volume 100 in :program:`MPD` corresponds to a 350% PulseAudio volume.
recorder recorder
~~~~~~~~ --------
The recorder plugin writes the audio played by :program:`MPD` to a file. This may be useful for recording radio streams. The recorder plugin writes the audio played by :program:`MPD` to a file. This may be useful for recording radio streams.
.. list-table:: .. list-table::
@@ -978,13 +985,13 @@ The recorder plugin writes the audio played by :program:`MPD` to a file. This ma
* - **path P** * - **path P**
- Write to this file. - Write to this file.
* - **format_path P** * - **format_path P**
- An alternative to path which provides a format string referring to tag values. The special tag iso8601 emits the current date and time in `ISO8601 <https://en.wikipedia.org/wiki/ISO_8601>`_ format (UTC). Every time a new song starts or a new tag gets received from a radio station, a new file is opened. If the format does not render a file name, nothing is recorded. A tag name enclosed in percent signs ('%') is replaced with the tag value. Example: :file:`~/.mpd/recorder/%artist% - %title%.ogg`. Square brackets can be used to group a substring. If none of the tags referred in the group can be found, the whole group is omitted. Example: [~/.mpd/recorder/[%artist% - ]%title%.ogg] (this omits the dash when no artist tag exists; if title also doesn't exist, no file is written). The operators "|" (logical "or") and "&" (logical "and") can be used to select portions of the format string depending on the existing tag values. Example: ~/.mpd/recorder/[%title%|%name%].ogg (use the "name" tag if no title exists) - An alternative to path which provides a format string referring to tag values. The special tag iso8601 emits the current date and time in `ISO8601 <https://en.wikipedia.org/wiki/ISO_8601>`_ format (UTC). Every time a new song starts or a new tag gets received from a radio station, a new file is opened. If the format does not render a file name, nothing is recorded. A tag name enclosed in percent signs ('%') is replaced with the tag value. Example: :file:`-/.mpd/recorder/%artist% - %title%.ogg`. Square brackets can be used to group a substring. If none of the tags referred in the group can be found, the whole group is omitted. Example: [-/.mpd/recorder/[%artist% - ]%title%.ogg] (this omits the dash when no artist tag exists; if title also doesn't exist, no file is written). The operators "|" (logical "or") and "&" (logical "and") can be used to select portions of the format string depending on the existing tag values. Example: -/.mpd/recorder/[%title%|%name%].ogg (use the "name" tag if no title exists)
* - **encoder NAME** * - **encoder NAME**
- Chooses an encoder plugin. A list of encoder plugins can be found in the encoder plugin reference :ref:`encoder_plugins`. - Chooses an encoder plugin. A list of encoder plugins can be found in the encoder plugin reference :ref:`encoder_plugins`.
shout shout
~~~~~ -----
The shout plugin connects to a ShoutCast or IceCast server using libshout. It forwards tags to this server. The shout plugin connects to a ShoutCast or IceCast server using libshout. It forwards tags to this server.
You must set a format. You must set a format.
@@ -1028,7 +1035,7 @@ You must set a format.
.. _sles_output: .. _sles_output:
sles sles
~~~~ ----
Plugin using the `OpenSL ES <https://www.khronos.org/opensles/>`__ Plugin using the `OpenSL ES <https://www.khronos.org/opensles/>`__
audio API. Its primary use is local playback on Android, where audio API. Its primary use is local playback on Android, where
@@ -1036,7 +1043,7 @@ audio API. Its primary use is local playback on Android, where
solaris solaris
~~~~~~~ -------
The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio. The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio.
.. list-table:: .. list-table::
@@ -1052,22 +1059,22 @@ The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio.
.. _filter_plugins: .. _filter_plugins:
Filter plugins Filter plugins
-------------- ==============
normalize normalize
~~~~~~~~~ ---------
Normalize the volume during playback (at the expensve of quality). Normalize the volume during playback (at the expensve of quality).
null null
~~~~ ----
A no-op filter. Audio data is returned as-is. A no-op filter. Audio data is returned as-is.
route route
~~~~~ -----
Reroute channels. Reroute channels.
@@ -1084,43 +1091,44 @@ Reroute channels.
.. _playlist_plugins: .. _playlist_plugins:
Playlist plugins Playlist plugins
---------------- ================
asx asx
~~~ ---
Reads .asx playlist files. Reads .asx playlist files.
cue cue
~~~ ---
Reads .cue files. Reads .cue files.
embcue embcue
~~~~~~ ------
Reads CUE sheets from the "CUESHEET" tag of song files. Reads CUE sheets from the "CUESHEET" tag of song files.
m3u m3u
~~~ ---
Reads .m3u playlist files. Reads .m3u playlist files.
extm3u extm3u
~~~~~~ ------
Reads extended .m3u playlist files. Reads extended .m3u playlist files.
flac flac
~~~~ ----
Reads the cuesheet metablock from a FLAC file. Reads the cuesheet metablock from a FLAC file.
pls pls
~~~ ---
Reads .pls playlist files. Reads .pls playlist files.
rss rss
~~~ ---
Reads music links from .rss files. Reads music links from .rss files.
soundcloud soundcloud
~~~~~~~~~~ ----------
Download playlist from SoundCloud. It accepts URIs starting with soundcloud://. Download playlist from SoundCloud. It accepts URIs starting with soundcloud://.
.. list-table:: .. list-table::
@@ -1133,5 +1141,5 @@ Download playlist from SoundCloud. It accepts URIs starting with soundcloud://.
- An API key to access the SoundCloud servers. - An API key to access the SoundCloud servers.
xspf xspf
~~~~ ----
Reads XSPF playlist files. Reads XSPF playlist files.

View File

@@ -14,6 +14,9 @@ Once the client is connected to the server, they conduct a
conversation until the client closes the connection. The conversation until the client closes the connection. The
conversation flow is always initiated by the client. conversation flow is always initiated by the client.
All data between the client and the server is encoded in
UTF-8.
The client transmits a command sequence, terminated by the The client transmits a command sequence, terminated by the
newline character ``\n``. The server will newline character ``\n``. The server will
respond with one or more lines, the last of which will be a respond with one or more lines, the last of which will be a
@@ -42,9 +45,6 @@ quotation marks.
Argument strings are separated from the command and any other Argument strings are separated from the command and any other
arguments by linear white-space (' ' or '\\t'). arguments by linear white-space (' ' or '\\t').
All data between the client and the server is encoded in
UTF-8.
Responses Responses
========= =========
@@ -52,6 +52,28 @@ A command returns ``OK`` on completion or
``ACK some error`` on failure. These ``ACK some error`` on failure. These
denote the end of command execution. denote the end of command execution.
Some commands return more data before the response ends with ``OK``.
Each line is usually in the form ``NAME: VALUE``. Example::
foo: bar
OK
.. _binary:
Binary Responses
----------------
Some commands can return binary data. This is initiated by a line
containing ``binary: 1234`` (followed as usual by a newline). After
that, the specified number of bytes of binary data follows, then a
newline, and finally the ``OK`` line. Example::
foo: bar
binary: 42
<42 bytes>
OK
Failure responses Failure responses
----------------- -----------------
@@ -112,9 +134,9 @@ list begins with `command_list_begin` or
`command_list_ok_begin` and ends with `command_list_ok_begin` and ends with
`command_list_end`. `command_list_end`.
It does not execute any commands until the list has ended. It does not execute any commands until the list has ended. The
The return value is whatever the return for a list of commands response is a concatentation of all individual responses.
is. On success for all commands, On success for all commands,
``OK`` is returned. If a command ``OK`` is returned. If a command
fails, no more commands are executed and the appropriate fails, no more commands are executed and the appropriate
``ACK`` error is returned. If ``ACK`` error is returned. If
@@ -178,8 +200,9 @@ of:
file's time stamp with the given value (ISO 8601 or UNIX file's time stamp with the given value (ISO 8601 or UNIX
time stamp). time stamp).
- ``(AudioFormat == 'SAMPLERATE:BITS:CHANNELS')``: - ``(AudioFormat == 'SAMPLERATE:BITS:CHANNELS')``: compares the audio
compares the audio format with the given value. format with the given value. See :ref:`audio_output_format` for a
detailed explanation.
- ``(AudioFormat =~ 'SAMPLERATE:BITS:CHANNELS')``: - ``(AudioFormat =~ 'SAMPLERATE:BITS:CHANNELS')``:
matches the audio format with the given mask (i.e. one matches the audio format with the given mask (i.e. one
@@ -414,15 +437,18 @@ Querying :program:`MPD`'s status
- ``songid``: playlist songid of the current song stopped on or playing - ``songid``: playlist songid of the current song stopped on or playing
- ``nextsong`` [#since_0_15]_: playlist song number of the next song to be played - ``nextsong`` [#since_0_15]_: playlist song number of the next song to be played
- ``nextsongid`` [#since_0_15]_: playlist songid of the next song to be played - ``nextsongid`` [#since_0_15]_: playlist songid of the next song to be played
- ``time``: total time elapsed (of current playing/paused song) - ``time``: total time elapsed (of current playing/paused song) in seconds
(deprecated, use ``elapsed`` instead) (deprecated, use ``elapsed`` instead)
- ``elapsed`` [#since_0_16]_: Total time elapsed within the current song, but with higher resolution. - ``elapsed`` [#since_0_16]_: Total time elapsed within the
current song in seconds, but with higher resolution.
- ``duration`` [#since_0_20]_: Duration of the current song in seconds. - ``duration`` [#since_0_20]_: Duration of the current song in seconds.
- ``bitrate``: instantaneous bitrate in kbps - ``bitrate``: instantaneous bitrate in kbps
- ``xfade``: ``crossfade`` in seconds - ``xfade``: ``crossfade`` in seconds
- ``mixrampdb``: ``mixramp`` threshold in dB - ``mixrampdb``: ``mixramp`` threshold in dB
- ``mixrampdelay``: ``mixrampdelay`` in seconds - ``mixrampdelay``: ``mixrampdelay`` in seconds
- ``audio``: The format emitted by the decoder plugin during playback, format: ``*samplerate:bits:channels*``. Check the user manual for a detailed explanation. - ``audio``: The format emitted by the decoder plugin during
playback, format: ``samplerate:bits:channels``. See
:ref:`audio_output_format` for a detailed explanation.
- ``updating_db``: ``job id`` - ``updating_db``: ``job id``
- ``error``: if there is an error, returns message here - ``error``: if there is an error, returns message here
@@ -437,7 +463,7 @@ Querying :program:`MPD`'s status
- ``albums``: number of albums - ``albums``: number of albums
- ``songs``: number of songs - ``songs``: number of songs
- ``uptime``: daemon uptime in seconds - ``uptime``: daemon uptime in seconds
- ``db_playtime``: sum of all song times in the db - ``db_playtime``: sum of all song times in the database in seconds
- ``db_update``: last db update in UNIX time - ``db_update``: last db update in UNIX time
- ``playtime``: time length of music played - ``playtime``: time length of music played
@@ -599,7 +625,7 @@ Whenever possible, ids should be used.
Deletes the song ``SONGID`` from the Deletes the song ``SONGID`` from the
playlist playlist
:command:`move {FROM} [{START:END} | {TO}]` :command:`move [{FROM} | {START:END}] {TO}`
Moves the song at ``FROM`` or range of songs Moves the song at ``FROM`` or range of songs
at ``START:END`` [#since_0_15]_ to ``TO`` at ``START:END`` [#since_0_15]_ to ``TO``
in the playlist. in the playlist.
@@ -790,7 +816,7 @@ The music database
Returns the file size and actual number Returns the file size and actual number
of bytes read at the requested offset, followed of bytes read at the requested offset, followed
by the chunk requested as raw bytes, then a by the chunk requested as raw bytes (see :ref:`binary`), then a
newline and the completion code. newline and the completion code.
Example:: Example::
@@ -798,8 +824,7 @@ The music database
albumart albumart
size: 1024768 size: 1024768
binary: 8192 binary: 8192
<8192 bytes> <8192 bytes>OK
OK
:command:`count {FILTER} [group {GROUPTYPE}]` :command:`count {FILTER} [group {GROUPTYPE}]`
Count the number of songs and their total playtime in Count the number of songs and their total playtime in
@@ -860,8 +885,7 @@ The music database
:command:`list {TYPE} {FILTER} [group {GROUPTYPE}]` :command:`list {TYPE} {FILTER} [group {GROUPTYPE}]`
Lists unique tags values of the specified type. Lists unique tags values of the specified type.
``TYPE`` can be any tag supported by ``TYPE`` can be any tag supported by
:program:`MPD` or :program:`MPD`.
*file*.
Additional arguments may specify a :ref:`filter <filter_syntax>`. Additional arguments may specify a :ref:`filter <filter_syntax>`.
The *group* keyword may be used The *group* keyword may be used
@@ -872,6 +896,10 @@ The music database
list album group albumartist list album group albumartist
``list file`` was implemented in an early :program:`MPD` version,
but does not appear to make a lot of sense. It still works (to
avoid breaking compatibility), but is deprecated.
.. _command_listall: .. _command_listall:
:command:`listall [URI]` :command:`listall [URI]`
@@ -1053,7 +1081,8 @@ Stickers
"Stickers" [#since_0_15]_ are pieces of "Stickers" [#since_0_15]_ are pieces of
information attached to existing information attached to existing
:program:`MPD` objects (e.g. song files, :program:`MPD` objects (e.g. song files,
directories, albums). Clients can create arbitrary name/value directories, albums; but currently, they are only implemented for
song). Clients can create arbitrary name/value
pairs. :program:`MPD` itself does not assume pairs. :program:`MPD` itself does not assume
any special meaning in them. any special meaning in them.

View File

@@ -402,14 +402,9 @@ The following table lists the audio_output options valid for all plugins:
- The name of the plugin - The name of the plugin
* - **name** * - **name**
- The name of the audio output. It is visible to the client. Some plugins also use it internally, e.g. as a name registered in the PULSE server. - The name of the audio output. It is visible to the client. Some plugins also use it internally, e.g. as a name registered in the PULSE server.
* - **format** * - **format samplerate:bits:channels**
- Always open the audio output with the specified audio format samplerate:bits:channels), regardless of the format of the input file. This is optional for most plugins. - Always open the audio output with the specified audio format, regardless of the format of the input file. This is optional for most plugins.
See :ref:`audio_output_format` for a detailed description of the value.
Any of the three attributes may be an asterisk to specify that this attribute should not be enforced, example: 48000:16:*. *:*:* is equal to not having a format specification.
The following values are valid for bits: 8 (signed 8 bit integer samples), 16, 24 (signed 24 bit integer samples padded to 32 bit), 32 (signed 32 bit integer samples), f (32 bit floating point, -1.0 to 1.0), "dsd" means DSD (Direct Stream Digital). For DSD, there are special cases such as "dsd64", which allows you to omit the sample rate (e.g. dsd512:2 for stereo DSD512, i.e. 22.5792 MHz).
The sample rate is special for DSD: :program:`MPD` counts the number of bytes, not bits. Thus, a DSD "bit" rate of 22.5792 MHz (DSD512) is 2822400 from :program:`MPD`'s point of view (44100*512/8).
* - **enabed yes|no** * - **enabed yes|no**
- Specifies whether this audio output is enabled when :program:`MPD` is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. - Specifies whether this audio output is enabled when :program:`MPD` is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.
* - **tags yes|no** * - **tags yes|no**
@@ -504,13 +499,34 @@ reference.
Audio Format Settings Audio Format Settings
--------------------- ---------------------
Global Audio Format .. _audio_output_format:
~~~~~~~~~~~~~~~~~~~
The setting audio_output_format forces :program:`MPD` to use one audio format for all outputs. Doing that is usually not a good idea. The values are the same as in format in the audio_output section. Global Audio Format
^^^^^^^^^^^^^^^^^^^
The setting ``audio_output_format`` forces :program:`MPD` to use one
audio format for all outputs. Doing that is usually not a good idea.
The value is specified as ``samplerate:bits:channels``.
Any of the three attributes may be an asterisk to specify that this
attribute should not be enforced, example: ``48000:16:*``.
``*:*:*`` is equal to not having a format specification.
The following values are valid for bits: ``8`` (signed 8 bit integer
samples), ``16``, ``24`` (signed 24 bit integer samples padded to 32
bit), ``32`` (signed 32 bit integer samples), ``f`` (32 bit floating
point, -1.0 to 1.0), ``dsd`` means DSD (Direct Stream Digital). For
DSD, there are special cases such as ``dsd64``, which allows you to
omit the sample rate (e.g. ``dsd512:2`` for stereo DSD512,
i.e. 22.5792 MHz).
The sample rate is special for DSD: :program:`MPD` counts the number
of bytes, not bits. Thus, a DSD "bit" rate of 22.5792 MHz (DSD512) is
2822400 from :program:`MPD`'s point of view (44100*512/8).
Resampler Resampler
~~~~~~~~~ ^^^^^^^^^
Sometimes, music needs to be resampled before it can be played; for example, CDs use a sample rate of 44,100 Hz while many cheap audio chips can only handle 48,000 Hz. Resampling reduces the quality and consumes a lot of CPU. There are different options, some of them optimized for high quality and others for low CPU usage, but you can't have both at the same time. Often, the resampler is the component that is responsible for most of :program:`MPD`'s CPU usage. Since :program:`MPD` comes with high quality defaults, it may appear that :program:`MPD` consumes more CPU than other software. Sometimes, music needs to be resampled before it can be played; for example, CDs use a sample rate of 44,100 Hz while many cheap audio chips can only handle 48,000 Hz. Resampling reduces the quality and consumes a lot of CPU. There are different options, some of them optimized for high quality and others for low CPU usage, but you can't have both at the same time. Often, the resampler is the component that is responsible for most of :program:`MPD`'s CPU usage. Since :program:`MPD` comes with high quality defaults, it may appear that :program:`MPD` consumes more CPU than other software.
@@ -523,7 +539,7 @@ Client Connections
.. _listeners: .. _listeners:
Listeners Listeners
~~~~~~~~~ ^^^^^^^^^
The setting :code:`bind_to_address` specifies which addresses The setting :code:`bind_to_address` specifies which addresses
:program:`MPD` listens on for connections from clients. It can be :program:`MPD` listens on for connections from clients. It can be
@@ -566,7 +582,7 @@ used.
Permissions and Passwords Permissions and Passwords
~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^
By default, all clients are unauthenticated and have a full set of permissions. This can be restricted with the settings :code:`default_permissions` and :code:`password`. By default, all clients are unauthenticated and have a full set of permissions. This can be restricted with the settings :code:`default_permissions` and :code:`password`.
@@ -629,7 +645,7 @@ Other Settings
Section :ref:`tags` contains a list of supported tags. Section :ref:`tags` contains a list of supported tags.
The State File The State File
~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^
The state file is a file where :program:`MPD` saves and restores its state (play queue, playback position etc.) to keep it persistent across restarts and reboots. It is an optional setting. The state file is a file where :program:`MPD` saves and restores its state (play queue, playback position etc.) to keep it persistent across restarts and reboots. It is an optional setting.
@@ -647,7 +663,7 @@ The State File
- Auto-save the state file this number of seconds after each state change. Defaults to 120 (2 minutes). - Auto-save the state file this number of seconds after each state change. Defaults to 120 (2 minutes).
The Sticker Database The Sticker Database
~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^
"Stickers" are pieces of information attached to songs. Some clients "Stickers" are pieces of information attached to songs. Some clients
use them to store ratings and other volatile data. This feature use them to store ratings and other volatile data. This feature
@@ -664,7 +680,7 @@ requires :program:`SQLite`, compile-time configure option
- The location of the sticker database. - The location of the sticker database.
Resource Limitations Resource Limitations
~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^
These settings are various limitations to prevent :program:`MPD` from using too many resources (denial of service). These settings are various limitations to prevent :program:`MPD` from using too many resources (denial of service).
@@ -686,7 +702,7 @@ These settings are various limitations to prevent :program:`MPD` from using too
- The maximum size of the output buffer to a client (maximum response size). Default is 8192 (8 MiB). - The maximum size of the output buffer to a client (maximum response size). Default is 8192 (8 MiB).
Buffer Settings Buffer Settings
~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^
Do not change these unless you know what you are doing. Do not change these unless you know what you are doing.
@@ -700,7 +716,7 @@ Do not change these unless you know what you are doing.
- Adjust the size of the internal audio buffer. Default is 4096 (4 MiB). - Adjust the size of the internal audio buffer. Default is 4096 (4 MiB).
Zeroconf Zeroconf
~~~~~~~~ ^^^^^^^^
If Zeroconf support (`Avahi <http://avahi.org/>`_ or Apple's Bonjour) If Zeroconf support (`Avahi <http://avahi.org/>`_ or Apple's Bonjour)
was enabled at compile time with :code:`-Dzeroconf=...`, was enabled at compile time with :code:`-Dzeroconf=...`,
@@ -786,10 +802,12 @@ You can verify whether the real-time scheduler is active with the ps command:
The CLS column shows the CPU scheduler; TS is the normal scheduler; FF and RR are real-time schedulers. In this example, two threads use the real-time scheduler: the output thread and the rtio (real-time I/O) thread; these two are the important ones. The database update thread uses the idle scheduler ("IDL in ps), which only gets CPU when no other process needs it. The CLS column shows the CPU scheduler; TS is the normal scheduler; FF and RR are real-time schedulers. In this example, two threads use the real-time scheduler: the output thread and the rtio (real-time I/O) thread; these two are the important ones. The database update thread uses the idle scheduler ("IDL in ps), which only gets CPU when no other process needs it.
Note .. note::
~~~~
There is a rumor that real-time scheduling improves audio quality. That is not true. All it does is reduce the probability of skipping (audio buffer xruns) when the computer is under heavy load. There is a rumor that real-time scheduling improves audio
quality. That is not true. All it does is reduce the probability of
skipping (audio buffer xruns) when the computer is under heavy
load.
Using MPD Using MPD
********* *********
@@ -817,7 +835,7 @@ Depending on the size of your music collection and the speed of the storage, thi
To exclude a file from the update, create a file called :file:`.mpdignore` in its parent directory. Each line of that file may contain a list of shell wildcards. Matching files in the current directory and all subdirectories are excluded. To exclude a file from the update, create a file called :file:`.mpdignore` in its parent directory. Each line of that file may contain a list of shell wildcards. Matching files in the current directory and all subdirectories are excluded.
Mounting other storages into the music directory Mounting other storages into the music directory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:program:`MPD` has various storage plugins of which multiple instances can be "mounted" into the music directory. This way, you can use local music, file servers and USB sticks at the same time. Example: :program:`MPD` has various storage plugins of which multiple instances can be "mounted" into the music directory. This way, you can use local music, file servers and USB sticks at the same time. Example:
@@ -885,7 +903,7 @@ To verify if :program:`MPD` converts the audio format, enable verbose logging, a
.. code-block:: none .. code-block:: none
decoder: audio_format=44100:24:2, seekable=true decoder: audio_format=44100:24:2, seekable=true
output: opened plugin=alsa name="An ALSA output"audio_format=44100:16:2 output: opened plugin=alsa name="An ALSA output" audio_format=44100:16:2
output: converting from 44100:24:2 output: converting from 44100:24:2
This example shows that a 24 bit file is being played, but the sound chip cannot play 24 bit. It falls back to 16 bit, discarding 8 bit. This example shows that a 24 bit file is being played, but the sound chip cannot play 24 bit. It falls back to 16 bit, discarding 8 bit.
@@ -912,7 +930,7 @@ Check list for bit-perfect playback:
device (:samp:`hw:0,0` or similar). device (:samp:`hw:0,0` or similar).
* Don't use software volume (setting :code:`mixer_type`). * Don't use software volume (setting :code:`mixer_type`).
* Don't force :program:`MPD` to use a specific audio format (settings * Don't force :program:`MPD` to use a specific audio format (settings
:code:`format`, :code:`audio_output_format`). :code:`format`, :ref:`audio_output_format <audio_output_format>`).
* Verify that you are really doing bit-perfect playback using :program:`MPD`'s verbose log and :file:`/proc/asound/card*/pcm*p/sub*/hw_params`. Some DACs can also indicate the audio format. * Verify that you are really doing bit-perfect playback using :program:`MPD`'s verbose log and :file:`/proc/asound/card*/pcm*p/sub*/hw_params`. Some DACs can also indicate the audio format.
Direct Stream Digital (DSD) Direct Stream Digital (DSD)
@@ -963,18 +981,18 @@ Support
------- -------
Getting Help Getting Help
~~~~~~~~~~~~ ^^^^^^^^^^^^
The :program:`MPD` project runs a `forum <https://forum.musicpd.org/>`_ and an IRC channel (#mpd on Freenode) for requesting help. Visit the MPD help page for details on how to get help. The :program:`MPD` project runs a `forum <https://forum.musicpd.org/>`_ and an IRC channel (#mpd on Freenode) for requesting help. Visit the MPD help page for details on how to get help.
Common Problems Common Problems
~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^
1. Database 1. Database
^^^^^^^^^^^ """""""""""
Question: I can't see my music in the MPD database! Question: I can't see my music in the MPD database!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Check your :code:`music_directory` setting. * Check your :code:`music_directory` setting.
* Does the MPD user have read permission on all music files, and read+execute permission on all music directories (and all of their parent directories)? * Does the MPD user have read permission on all music files, and read+execute permission on all music directories (and all of their parent directories)?
@@ -982,22 +1000,22 @@ Question: I can't see my music in the MPD database!
* Did you enable all relevant decoder plugins at compile time? :command:`mpd --version` will tell you. * Did you enable all relevant decoder plugins at compile time? :command:`mpd --version` will tell you.
Question: MPD doesn't read ID3 tags! Question: MPD doesn't read ID3 tags!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* You probably compiled :program:`MPD` without libid3tag. :command:`mpd --version` will tell you. * You probably compiled :program:`MPD` without libid3tag. :command:`mpd --version` will tell you.
2. Playback 2. Playback
^^^^^^^^^^^ """""""""""
Question: I can't hear music on my client! Question: I can't hear music on my client!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* That problem usually follows a misunderstanding of the nature of :program:`MPD`. :program:`MPD` is a remote-controlled music player, not a music distribution system. Usually, the speakers are connected to the box where :program:`MPD` runs, and the :program:`MPD` client only sends control commands, but the client does not actually play your music. * That problem usually follows a misunderstanding of the nature of :program:`MPD`. :program:`MPD` is a remote-controlled music player, not a music distribution system. Usually, the speakers are connected to the box where :program:`MPD` runs, and the :program:`MPD` client only sends control commands, but the client does not actually play your music.
:program:`MPD` has output plugins which allow hearing music on a remote host (such as httpd), but that is not :program:`MPD`'s primary design goal. :program:`MPD` has output plugins which allow hearing music on a remote host (such as httpd), but that is not :program:`MPD`'s primary design goal.
Question: "Device or resource busy" Question: "Device or resource busy"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This ALSA error means that another program uses your sound hardware exclusively. You can stop that program to allow :program:`MPD` to use it. * This ALSA error means that another program uses your sound hardware exclusively. You can stop that program to allow :program:`MPD` to use it.
@@ -1016,7 +1034,7 @@ Your bug report should contain:
* be clear about what you expect MPD to do, and what is actually happening * be clear about what you expect MPD to do, and what is actually happening
MPD crashes MPD crashes
~~~~~~~~~~~ ^^^^^^^^^^^
All :program:`MPD` crashes are bugs which must be fixed by a developer, and you should write a bug report. (Many crash bugs are caused by codec libraries used by :program:`MPD`, and then that library must be fixed; but in any case, the :program:`MPD` `bug tracker <https://github.com/MusicPlayerDaemon/MPD/issues>`_ is a good place to report it first if you don't know.) All :program:`MPD` crashes are bugs which must be fixed by a developer, and you should write a bug report. (Many crash bugs are caused by codec libraries used by :program:`MPD`, and then that library must be fixed; but in any case, the :program:`MPD` `bug tracker <https://github.com/MusicPlayerDaemon/MPD/issues>`_ is a good place to report it first if you don't know.)

View File

@@ -1,7 +1,7 @@
project( project(
'mpd', 'mpd',
['c', 'cpp'], ['c', 'cpp'],
version: '0.21.7', version: '0.21.10',
meson_version: '>= 0.49.0', meson_version: '>= 0.49.0',
default_options: [ default_options: [
'c_std=c99', 'c_std=c99',
@@ -367,8 +367,10 @@ basic_dep = declare_dependency(
if enable_database if enable_database
subdir('src/storage') subdir('src/storage')
subdir('src/db') else
storage_glue_dep = dependency('', required: false)
endif endif
subdir('src/db')
if neighbor_glue_dep.found() if neighbor_glue_dep.found()
sources += 'src/command/NeighborCommands.cxx' sources += 'src/command/NeighborCommands.cxx'

View File

@@ -392,7 +392,7 @@ libnfs = AutotoolsProject(
) )
boost = BoostProject( boost = BoostProject(
'http://downloads.sourceforge.net/project/boost/boost/1.69.0/boost_1_69_0.tar.bz2', 'http://downloads.sourceforge.net/project/boost/boost/1.70.0/boost_1_70_0.tar.bz2',
'8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406', '430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778',
'include/boost/version.hpp', 'include/boost/version.hpp',
) )

View File

@@ -108,17 +108,17 @@ static constexpr Domain cmdline_domain("cmdline");
gcc_noreturn gcc_noreturn
static void version(void) static void version(void)
{ {
printf("Music Player Daemon " VERSION " (%s)\n" printf("Music Player Daemon " VERSION " (%s)"
"\n" "\n"
"Copyright 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n" "Copyright 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
"Copyright 2008-2018 Max Kellermann <max.kellermann@gmail.com>\n" "Copyright 2008-2018 Max Kellermann <max.kellermann@gmail.com>\n"
"This is free software; see the source for copying conditions. There is NO\n" "This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" "warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
GIT_VERSION);
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
"\n" printf("\n"
"Database plugins:\n", "Database plugins:\n");
GIT_VERSION);
for (auto i = database_plugins; *i != nullptr; ++i) for (auto i = database_plugins; *i != nullptr; ++i)
printf(" %s", (*i)->name); printf(" %s", (*i)->name);
@@ -129,18 +129,18 @@ static void version(void)
for (auto i = storage_plugins; *i != nullptr; ++i) for (auto i = storage_plugins; *i != nullptr; ++i)
printf(" %s", (*i)->name); printf(" %s", (*i)->name);
printf("\n" printf("\n");
#endif #endif
#ifdef ENABLE_NEIGHBOR_PLUGINS #ifdef ENABLE_NEIGHBOR_PLUGINS
"\n" printf("\n"
"Neighbor plugins:\n"); "Neighbor plugins:\n");
for (auto i = neighbor_plugins; *i != nullptr; ++i) for (auto i = neighbor_plugins; *i != nullptr; ++i)
printf(" %s", (*i)->name); printf(" %s", (*i)->name);
printf("\n"
#endif #endif
printf("\n"
"\n" "\n"
"Decoders plugins:\n"); "Decoders plugins:\n");

View File

@@ -55,14 +55,26 @@ LocateFileUri(const char *uri, const Client *client
} }
static LocatedUri static LocatedUri
LocateAbsoluteUri(const char *uri LocateAbsoluteUri(UriPluginKind kind, const char *uri
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, const Storage *storage , const Storage *storage
#endif #endif
) )
{ {
if (!uri_supported_scheme(uri)) switch (kind) {
throw std::runtime_error("Unsupported URI scheme"); case UriPluginKind::INPUT:
case UriPluginKind::STORAGE: // TODO: separate check for storage plugins
if (!uri_supported_scheme(uri))
throw std::runtime_error("Unsupported URI scheme");
break;
case UriPluginKind::PLAYLIST:
/* for now, no validation for playlist URIs; this is
more complicated because there are three ways to
identify which plugin to use: URI scheme, filename
suffix and MIME type */
break;
}
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
if (storage != nullptr) { if (storage != nullptr) {
@@ -76,7 +88,8 @@ LocateAbsoluteUri(const char *uri
} }
LocatedUri LocatedUri
LocateUri(const char *uri, const Client *client LocateUri(UriPluginKind kind,
const char *uri, const Client *client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, const Storage *storage , const Storage *storage
#endif #endif
@@ -100,7 +113,7 @@ LocateUri(const char *uri, const Client *client
#endif #endif
); );
else if (uri_has_scheme(uri)) else if (uri_has_scheme(uri))
return LocateAbsoluteUri(uri return LocateAbsoluteUri(kind, uri
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, storage , storage
#endif #endif

View File

@@ -41,6 +41,12 @@ class Client;
class Storage; class Storage;
#endif #endif
enum class UriPluginKind {
INPUT,
STORAGE,
PLAYLIST,
};
struct LocatedUri { struct LocatedUri {
enum class Type { enum class Type {
/** /**
@@ -84,7 +90,8 @@ struct LocatedUri {
* that feature is disabled if this parameter is nullptr * that feature is disabled if this parameter is nullptr
*/ */
LocatedUri LocatedUri
LocateUri(const char *uri, const Client *client LocateUri(UriPluginKind kind,
const char *uri, const Client *client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, const Storage *storage , const Storage *storage
#endif #endif

View File

@@ -94,7 +94,8 @@ SongLoader::LoadSong(const char *uri_utf8) const
assert(uri_utf8 != nullptr); assert(uri_utf8 != nullptr);
#endif #endif
const auto located_uri = LocateUri(uri_utf8, client const auto located_uri = LocateUri(UriPluginKind::INPUT,
uri_utf8, client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, storage , storage
#endif #endif

View File

@@ -218,7 +218,7 @@ handle_read_comments(Client &client, Request args, Response &r)
const char *const uri = args.front(); const char *const uri = args.front();
const auto located_uri = LocateUri(uri, &client const auto located_uri = LocateUri(UriPluginKind::INPUT, uri, &client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, nullptr , nullptr
#endif #endif
@@ -331,7 +331,7 @@ handle_album_art(Client &client, Request args, Response &r)
const char *uri = args.front(); const char *uri = args.front();
size_t offset = args.ParseUnsigned(1); size_t offset = args.ParseUnsigned(1);
const auto located_uri = LocateUri(uri, &client const auto located_uri = LocateUri(UriPluginKind::INPUT, uri, &client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, nullptr , nullptr
#endif #endif

View File

@@ -99,7 +99,7 @@ handle_listfiles(Client &client, Request args, Response &r)
/* default is root directory */ /* default is root directory */
const auto uri = args.GetOptional(0, ""); const auto uri = args.GetOptional(0, "");
const auto located_uri = LocateUri(uri, &client const auto located_uri = LocateUri(UriPluginKind::STORAGE, uri, &client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, nullptr , nullptr
#endif #endif
@@ -219,7 +219,7 @@ handle_lsinfo(Client &client, Request args, Response &r)
compatibility, work around this here */ compatibility, work around this here */
uri = ""; uri = "";
const auto located_uri = LocateUri(uri, &client const auto located_uri = LocateUri(UriPluginKind::INPUT, uri, &client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, nullptr , nullptr
#endif #endif

View File

@@ -69,7 +69,8 @@ handle_save(Client &client, Request args, gcc_unused Response &r)
CommandResult CommandResult
handle_load(Client &client, Request args, gcc_unused Response &r) handle_load(Client &client, Request args, gcc_unused Response &r)
{ {
const auto uri = LocateUri(args.front(), &client const auto uri = LocateUri(UriPluginKind::PLAYLIST, args.front(),
&client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, nullptr , nullptr
#endif #endif
@@ -99,7 +100,8 @@ handle_load(Client &client, Request args, gcc_unused Response &r)
CommandResult CommandResult
handle_listplaylist(Client &client, Request args, Response &r) handle_listplaylist(Client &client, Request args, Response &r)
{ {
const auto name = LocateUri(args.front(), &client const auto name = LocateUri(UriPluginKind::PLAYLIST, args.front(),
&client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, nullptr , nullptr
#endif #endif
@@ -115,7 +117,8 @@ handle_listplaylist(Client &client, Request args, Response &r)
CommandResult CommandResult
handle_listplaylistinfo(Client &client, Request args, Response &r) handle_listplaylistinfo(Client &client, Request args, Response &r)
{ {
const auto name = LocateUri(args.front(), &client const auto name = LocateUri(UriPluginKind::PLAYLIST, args.front(),
&client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, nullptr , nullptr
#endif #endif

View File

@@ -83,7 +83,8 @@ handle_add(Client &client, Request args, Response &r)
here */ here */
uri = ""; uri = "";
const auto located_uri = LocateUri(uri, &client const auto located_uri = LocateUri(UriPluginKind::INPUT, uri,
&client
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
, nullptr , nullptr
#endif #endif

View File

@@ -9,6 +9,11 @@ db_api_dep = declare_dependency(
link_with: db_api, link_with: db_api,
) )
if not enable_database
db_glue_dep = db_api_dep
subdir_done()
endif
subdir('plugins') subdir('plugins')
db_glue_sources = [ db_glue_sources = [

View File

@@ -568,7 +568,8 @@ ProxyDatabase::OnSocketReady(gcc_unused unsigned flags) noexcept
if (!is_idle) { if (!is_idle) {
// TODO: can this happen? // TODO: can this happen?
IdleMonitor::Schedule(); IdleMonitor::Schedule();
return false; SocketMonitor::Cancel();
return true;
} }
unsigned idle = (unsigned)mpd_recv_idle(connection, false); unsigned idle = (unsigned)mpd_recv_idle(connection, false);
@@ -586,7 +587,8 @@ ProxyDatabase::OnSocketReady(gcc_unused unsigned flags) noexcept
idle_received |= idle; idle_received |= idle;
is_idle = false; is_idle = false;
IdleMonitor::Schedule(); IdleMonitor::Schedule();
return false; SocketMonitor::Cancel();
return true;
} }
void void

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2003-2018 The Music Player Daemon Project * Copyright 2003-2019 The Music Player Daemon Project
* http://www.musicpd.org * http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,8 @@
#ifndef MPD_OPUS_READER_HXX #ifndef MPD_OPUS_READER_HXX
#define MPD_OPUS_READER_HXX #define MPD_OPUS_READER_HXX
#include "util/StringView.hxx"
#include <algorithm> #include <algorithm>
#include <stdint.h> #include <stdint.h>
@@ -81,18 +83,16 @@ public:
return ReadWord(length) && Skip(length); return ReadWord(length) && Skip(length);
} }
char *ReadString() { StringView ReadString() {
uint32_t length; uint32_t length;
if (!ReadWord(length) || length >= 65536) if (!ReadWord(length))
return nullptr; return nullptr;
const char *src = (const char *)Read(length); const char *src = (const char *)Read(length);
if (src == nullptr) if (src == nullptr)
return nullptr; return nullptr;
char *dest = new char[length + 1]; return {src, length};
*std::copy_n(src, length, dest) = 0;
return dest;
} }
}; };

View File

@@ -24,6 +24,8 @@
#include "tag/ParseName.hxx" #include "tag/ParseName.hxx"
#include "ReplayGainInfo.hxx" #include "ReplayGainInfo.hxx"
#include <string>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@@ -91,18 +93,25 @@ ScanOpusTags(const void *data, size_t size,
return false; return false;
while (n-- > 0) { while (n-- > 0) {
char *p = r.ReadString(); const auto s = r.ReadString();
if (p == nullptr) if (s == nullptr)
return false; return false;
char *eq = strchr(p, '='); if (s.size >= 4096)
if (eq != nullptr && eq > p) { continue;
*eq = 0;
ScanOneOpusTag(p, eq + 1, rgi, handler); const auto eq = s.Find('=');
} if (eq == nullptr || eq == s.data)
continue;
delete[] p; auto name = s, value = s;
name.SetEnd(eq);
value.MoveFront(eq + 1);
const std::string name2(name.data, name.size);
const std::string value2(value.data, value.size);
ScanOneOpusTag(name2.c_str(), value2.c_str(), rgi, handler);
} }
return true; return true;

View File

@@ -110,15 +110,9 @@ BufferedSocket::OnSocketReady(unsigned flags) noexcept
if (flags & READ) { if (flags & READ) {
assert(!input.IsFull()); assert(!input.IsFull());
if (!ReadToBuffer()) if (!ReadToBuffer() || !ResumeInput())
return false; return false;
if (!ResumeInput())
/* we must return "true" here or
SocketMonitor::Dispatch() will call
Cancel() on a freed object */
return true;
if (!input.IsFull()) if (!input.IsFull())
ScheduleRead(); ScheduleRead();
} }

View File

@@ -46,6 +46,11 @@ public:
using SocketMonitor::Close; using SocketMonitor::Close;
private: private:
/**
* @return the number of bytes read from the socket, 0 if the
* socket isn't ready for reading, -1 on error (the socket has
* been closed and probably destructed)
*/
ssize_t DirectRead(void *data, size_t length) noexcept; ssize_t DirectRead(void *data, size_t length) noexcept;
/** /**

View File

@@ -45,6 +45,11 @@ public:
} }
private: private:
/**
* @return the number of bytes written to the socket, 0 if the
* socket isn't ready for writing, -1 on error (the socket has
* been closed and probably destructed)
*/
ssize_t DirectWrite(const void *data, size_t length) noexcept; ssize_t DirectWrite(const void *data, size_t length) noexcept;
protected: protected:

View File

@@ -33,8 +33,8 @@ SocketMonitor::Dispatch(unsigned flags) noexcept
{ {
flags &= GetScheduledFlags(); flags &= GetScheduledFlags();
if (flags != 0 && !OnSocketReady(flags) && IsDefined()) if (flags != 0)
Cancel(); OnSocketReady(flags);
} }
SocketMonitor::~SocketMonitor() noexcept SocketMonitor::~SocketMonitor() noexcept

View File

@@ -59,6 +59,9 @@ BufferedInputStream::~BufferedInputStream() noexcept
void void
BufferedInputStream::Check() BufferedInputStream::Check()
{ {
if (read_error)
std::rethrow_exception(read_error);
if (input) if (input)
input->Check(); input->Check();
} }
@@ -101,7 +104,7 @@ BufferedInputStream::IsEOF() noexcept
bool bool
BufferedInputStream::IsAvailable() noexcept BufferedInputStream::IsAvailable() noexcept
{ {
return IsEOF() || buffer.Read(offset).HasData(); return IsEOF() || buffer.Read(offset).HasData() || read_error;
} }
size_t size_t
@@ -164,6 +167,32 @@ BufferedInputStream::RunThread() noexcept
idle = false; idle = false;
seek = false; seek = false;
client_cond.signal(); client_cond.signal();
} else if (!idle && !read_error &&
offset != input->GetOffset() &&
!IsAvailable()) {
/* a past Seek() call was a no-op because data
was already available at that position, but
now we've reached a new position where
there is no more data in the buffer, and
our input is reading somewhere else (maybe
stuck at the end of the file); to find a
way out, we now seek our input to our
reading position to be able to fill our
buffer */
try {
input->Seek(offset);
} catch (...) {
/* this is really a seek error, but we
register it as a read_error,
because seek_error is only checked
by Seek(), and at our frontend (our
own InputStream interface) is in
"read" mode */
read_error = std::current_exception();
client_cond.signal();
InvokeOnAvailable();
}
} else if (!idle && !read_error && } else if (!idle && !read_error &&
input->IsAvailable() && !input->IsEOF()) { input->IsAvailable() && !input->IsEOF()) {
const auto read_offset = input->GetOffset(); const auto read_offset = input->GetOffset();

View File

@@ -22,6 +22,7 @@
#include "lib/smbclient/Mutex.hxx" #include "lib/smbclient/Mutex.hxx"
#include "../InputStream.hxx" #include "../InputStream.hxx"
#include "../InputPlugin.hxx" #include "../InputPlugin.hxx"
#include "../MaybeBufferedInputStream.hxx"
#include "PluginUnavailable.hxx" #include "PluginUnavailable.hxx"
#include "system/Error.hxx" #include "system/Error.hxx"
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
@@ -112,8 +113,9 @@ input_smbclient_open(const char *uri,
throw MakeErrno(e, "smbc_fstat() failed"); throw MakeErrno(e, "smbc_fstat() failed");
} }
return std::make_unique<SmbclientInputStream>(uri, mutex, return std::make_unique<MaybeBufferedInputStream>
ctx, fd, st); (std::make_unique<SmbclientInputStream>(uri, mutex,
ctx, fd, st));
} }
size_t size_t

View File

@@ -150,8 +150,6 @@ ReadServers(NeighborExplorer::List &list, int fd)
smbc_dirent *e; smbc_dirent *e;
while ((e = smbc_readdir(fd)) != nullptr) while ((e = smbc_readdir(fd)) != nullptr)
ReadEntry(list, *e); ReadEntry(list, *e);
smbc_closedir(fd);
} }
static void static void

View File

@@ -168,7 +168,7 @@ public:
} }
constexpr operator SocketAddress() const noexcept { constexpr operator SocketAddress() const noexcept {
return SocketAddress((const struct sockaddr *)&address, return SocketAddress((const struct sockaddr *)(const void *)&address,
sizeof(address)); sizeof(address));
} }

View File

@@ -135,7 +135,7 @@ public:
} }
constexpr operator SocketAddress() const noexcept { constexpr operator SocketAddress() const noexcept {
return SocketAddress((const struct sockaddr *)&address, return SocketAddress((const struct sockaddr *)(const void *)&address,
sizeof(address)); sizeof(address));
} }

View File

@@ -71,10 +71,10 @@ HttpdClient::HandleLine(const char *line) noexcept
assert(state != State::RESPONSE); assert(state != State::RESPONSE);
if (state == State::REQUEST) { if (state == State::REQUEST) {
if (memcmp(line, "HEAD /", 6) == 0) { if (strncmp(line, "HEAD /", 6) == 0) {
line += 6; line += 6;
head_method = true; head_method = true;
} else if (memcmp(line, "GET /", 5) == 0) { } else if (strncmp(line, "GET /", 5) == 0) {
line += 5; line += 5;
} else { } else {
/* only GET is supported */ /* only GET is supported */
@@ -83,8 +83,19 @@ HttpdClient::HandleLine(const char *line) noexcept
return false; return false;
} }
/* blacklist some well-known request paths */
if ((strncmp(line, "favicon.ico", 11) == 0 &&
(line[11] == '\0' || line[11] == ' ')) ||
(strncmp(line, "robots.txt", 10) == 0 &&
(line[10] == '\0' || line[10] == ' ')) ||
(strncmp(line, "sitemap.xml", 11) == 0 &&
(line[11] == '\0' || line[11] == ' ')) ||
(strncmp(line, ".well-known/", 12) == 0)) {
should_reject = true;
}
line = strchr(line, ' '); line = strchr(line, ' ');
if (line == nullptr || memcmp(line + 1, "HTTP/", 5) != 0) { if (line == nullptr || strncmp(line + 1, "HTTP/", 5) != 0) {
/* HTTP/0.9 without request headers */ /* HTTP/0.9 without request headers */
if (head_method) if (head_method)
@@ -129,14 +140,21 @@ HttpdClient::SendResponse() noexcept
assert(state == State::RESPONSE); assert(state == State::RESPONSE);
if (metadata_requested) { if (should_reject) {
response =
"HTTP/1.1 404 not found\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n"
"\r\n"
"404 not found";
} else if (metadata_requested) {
allocated = allocated =
icy_server_metadata_header(httpd.name, httpd.genre, icy_server_metadata_header(httpd.name, httpd.genre,
httpd.website, httpd.website,
httpd.content_type, httpd.content_type,
metaint); metaint);
response = allocated.c_str(); response = allocated.c_str();
} else { /* revert to a normal HTTP request */ } else { /* revert to a normal HTTP request */
snprintf(buffer, sizeof(buffer), snprintf(buffer, sizeof(buffer),
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n" "Content-Type: %s\r\n"
@@ -154,7 +172,7 @@ HttpdClient::SendResponse() noexcept
FormatWarning(httpd_output_domain, FormatWarning(httpd_output_domain,
"failed to write to client: %s", "failed to write to client: %s",
(const char *)msg); (const char *)msg);
Close(); LockClose();
return false; return false;
} }
@@ -415,7 +433,7 @@ HttpdClient::OnSocketInput(void *data, size_t length) noexcept
if (!SendResponse()) if (!SendResponse())
return InputResult::CLOSED; return InputResult::CLOSED;
if (head_method) { if (head_method || should_reject) {
LockClose(); LockClose();
return InputResult::CLOSED; return InputResult::CLOSED;
} }
@@ -428,6 +446,7 @@ void
HttpdClient::OnSocketError(std::exception_ptr ep) noexcept HttpdClient::OnSocketError(std::exception_ptr ep) noexcept
{ {
LogError(ep); LogError(ep);
LockClose();
} }
void void

View File

@@ -83,6 +83,11 @@ class HttpdClient final
*/ */
bool head_method = false; bool head_method = false;
/**
* Should we reject this request?
*/
bool should_reject = false;
/* ICY */ /* ICY */
/** /**
@@ -142,6 +147,8 @@ public:
/** /**
* Frees the client and removes it from the server's client list. * Frees the client and removes it from the server's client list.
*
* Caller must lock the mutex.
*/ */
void Close() noexcept; void Close() noexcept;

View File

@@ -208,10 +208,15 @@ public:
return HasClients(); return HasClients();
} }
/**
* Caller must lock the mutex.
*/
void AddClient(UniqueSocketDescriptor fd) noexcept; void AddClient(UniqueSocketDescriptor fd) noexcept;
/** /**
* Removes a client from the httpd_output.clients linked list. * Removes a client from the httpd_output.clients linked list.
*
* Caller must lock the mutex.
*/ */
void RemoveClient(HttpdClient &client) noexcept; void RemoveClient(HttpdClient &client) noexcept;
@@ -239,10 +244,14 @@ public:
/** /**
* Broadcasts data from the encoder to all clients. * Broadcasts data from the encoder to all clients.
*
* Mutext must not be locked.
*/ */
void BroadcastFromEncoder(); void BroadcastFromEncoder();
/** /**
* Mutext must not be locked.
*
* Throws #std::runtime_error on error. * Throws #std::runtime_error on error.
*/ */
void EncodeAndPlay(const void *chunk, size_t size); void EncodeAndPlay(const void *chunk, size_t size);
@@ -251,6 +260,9 @@ public:
size_t Play(const void *chunk, size_t size) override; size_t Play(const void *chunk, size_t size) override;
/**
* Mutext must not be locked.
*/
void CancelAllClients() noexcept; void CancelAllClients() noexcept;
void Cancel() noexcept override; void Cancel() noexcept override;

View File

@@ -996,7 +996,7 @@ Player::Run() noexcept
} }
} }
if (dc.IsIdle() && queued && dc.pipe == pipe) { if (dc.IsIdle() && queued && IsDecoderAtCurrentSong()) {
/* the decoder has finished the current song; /* the decoder has finished the current song;
make it decode the next song */ make it decode the next song */
@@ -1058,6 +1058,16 @@ Player::Run() noexcept
SongBorder(); SongBorder();
} else if (dc.IsIdle()) { } else if (dc.IsIdle()) {
if (queued)
/* the decoder has just stopped,
between the two IsIdle() checks,
probably while UnlockCheckOutputs()
left the mutex unlocked; to restart
the decoder instead of stopping
playback completely, let's re-enter
this loop */
continue;
/* check the size of the pipe again, because /* check the size of the pipe again, because
the decoder thread may have added something the decoder thread may have added something
since we last checked */ since we last checked */

View File

@@ -50,7 +50,7 @@ protected:
/* virtual methods from class SocketMonitor */ /* virtual methods from class SocketMonitor */
bool OnSocketReady(gcc_unused unsigned flags) noexcept override { bool OnSocketReady(gcc_unused unsigned flags) noexcept override {
DNSServiceProcessResult(service_ref); DNSServiceProcessResult(service_ref);
return false; return true;
} }
}; };

View File

@@ -1,5 +1,5 @@
[Socket] [Socket]
ListenStream=/run/mpd/socket ListenStream=%t/mpd/socket
ListenStream=6600 ListenStream=6600
Backlog=5 Backlog=5
KeepAlive=true KeepAlive=true

View File

@@ -3,6 +3,12 @@ if systemd_user_unit_dir == ''
systemd_user_unit_dir = join_paths(get_option('prefix'), 'lib', 'systemd', 'user') systemd_user_unit_dir = join_paths(get_option('prefix'), 'lib', 'systemd', 'user')
endif endif
# copy the system socket unit to the "user" directory
install_data(
join_paths('..', 'system', 'mpd.socket'),
install_dir: systemd_user_unit_dir,
)
configure_file( configure_file(
input: 'mpd.service.in', input: 'mpd.service.in',
output: 'mpd.service', output: 'mpd.service',