Compare commits

...

41 Commits

Author SHA1 Message Date
Max Kellermann
49b9a90c3f release v0.20.13 2017-12-18 23:41:56 +01:00
FlashSystems
64d141f71e Save and restore mountpoints within the state file.
Signed-off-by: FlashSystems <developer@flashsystems.de>
2017-12-18 23:39:01 +01:00
FlashSystems
c488d3123f Fix lsinfo and add for mounted databases.
If `SimpleDatabase::Visit` is called on a database that contains a mounted directry the URIs of the elements passed to the callbacks are not prefixed by the mountpoint path. This leads to lsinfo and add not working because they use the wrong URI. This pull request is using the `WalkMount` helper function to create prefixed versions of `VisitDirectory`, `VisitSong` and `VisitPlaylist` to add the correct prefix to the parameters of the callback functions.
2017-12-18 23:33:08 +01:00
Stefano Miccoli
967af60327 rounds alsa HW mixer volume towards ±∞ depending on sgn(∆ vol)
This alleviates a problem in which 'volume +1' cannot be undo by
'volume -1' when using alsa hw mixer.

Closes 
2017-12-18 21:29:03 +01:00
Yue Wang
f1ef9f9d31 OSXOutputPlugin: set the buffer time to be 100ms
[mk: the following text was copied from
https://github.com/MusicPlayerDaemon/MPD/pull/167]

For certain format (hi-res files) and normal buffer size hardware, The
hardware may at once consume most of the buffers. However, in Delay()
function, MPD is supposed to wait for 25 ms after the next try. it
will create a hiccup. The negative impact is much major than
increasing the latency.

I understand larger buffers come at a price. That's why in my earlier
commit last year I significantly reduced it. However, the buffer size
in CoreAudio is set according to the hardware, which is super small
latency. For instance, the system audio of 2015 generation of macbook
pro has maximum buffer size of 4096 samples, which is just 0.09s for
44.1k framerate, or 0.04s for 96k frames --- . compare to the 0.5 sec
latency alsa plugin has, even if we quadruple it, it's still super
tiny.
2017-12-12 10:56:42 +01:00
Max Kellermann
dfaf08743c *: check defined(_WIN32) instead of defined(WIN32)
Only _WIN32 is defined by the compiler, and WIN32 is not standardized
and may be missing.

Closes 
2017-12-12 10:22:20 +01:00
Max Kellermann
d9552d8a6d android/build.py: support NDK r16 2017-12-12 10:01:47 +01:00
Max Kellermann
7586a8ab2c python/build/libs.py: disable the FFmpeg HEVC decoder due to clang build failure 2017-12-12 10:01:47 +01:00
Max Kellermann
e1a942250b python/build/libs.py: disable more FFmpeg features 2017-12-12 09:57:40 +01:00
Max Kellermann
72be0185de python/libs: upgrade Boost to 1.65.1 2017-12-12 09:16:40 +01:00
Max Kellermann
7e4cbce06b python/build/libs: upgrade CURL to 7.57.0 2017-12-12 09:15:24 +01:00
Max Kellermann
177d62f431 python/build/libs: upgrade FFmpeg to 3.4.1 2017-12-11 19:00:22 +01:00
Uwe Kleine-König
5a11e03725 lib/upnp: use include path without upnp/ prefix and honor pkg-config CFLAGS
If libupnp is installed in a non-standard location we must rely on the
include path provided by $(pkg-config --cflags libupnp). Relative to the
path given from that command no prefix must be used to find the respective
files.
2017-12-11 18:58:09 +01:00
Max Kellermann
75d068b7cd Makefile.am: include Windows cross-build script in source tarball 2017-12-05 11:24:52 +01:00
FlashSystems
1208503888 Removing gcc_malloc attribute from Directory::CreateChild to fix
assignment of `mnt->mounted_database` in `SimpleDatabase::Mount`.
2017-12-03 12:34:08 +01:00
Max Kellermann
de90d401d2 MusicChunk: add magic value IGNORE_REPLAY_GAIN
This fixes spurious replay gain logs when the player inserts silence
chunks, because those silence chunks had no replay gain attached,
resetting the ReplayGainFilter state, flipping it forth and back.
2017-12-03 11:39:12 +01:00
Max Kellermann
396defaea9 MusicChunk: initialize replay_gain_serial on demand 2017-12-03 11:39:07 +01:00
Max Kellermann
18f350cd04 player/Thread: initialize MusicChunk::bit_rate in SendSilence()
This attribute is not particularly important, but it was
uninitialized.
2017-12-03 10:54:14 +01:00
Max Kellermann
478180ebe4 queue/PlaylistEdit: shuffle appended songs only within its priority group
Fixes .
2017-12-02 17:17:02 +01:00
Max Kellermann
4a3059f509 queue/PlaylistControl: don't skip highest priority song on "play"
When starting playback with a specific song which does not have the
highest priority, the previous highest priority song was skipped
completely because its order was "swapped".  This commit changes to a
more expensive operation which inserts the selected song into the
order list.

This fixes a small part of 
2017-12-02 16:25:32 +01:00
Max Kellermann
78728138a0 lib/upnp/Compat: disable the 1.8 API emulation with libupnp 1.6.24
libupnp 1.6.24 added a few badly designed macros which break the MPD
build:

 8177a4195a/

To work around this, we disable our emulation functions (from
714011c81e) on this libupnp version.

Closes 
2017-12-02 14:47:27 +01:00
FlashSystems
63fc98591d Fix for "Mount-Points are purged from database on update/rescan."
Signed-off-by: FlashSystems <developer@flashsystems.de>
2017-11-27 22:34:49 +01:00
Max Kellermann
53def9a682 increment version number to 0.20.13 2017-11-27 22:32:55 +01:00
Max Kellermann
323231d1dd release v0.20.12 2017-11-25 19:32:37 +01:00
Max Kellermann
714011c81e lib/upnp: adapt to libupnp 1.8 API changes
Closes 
2017-11-16 11:39:11 +01:00
Max Kellermann
952ff4207b lib/upnp/Callback: make "evp" parameter const 2017-11-16 11:37:58 +01:00
Max Kellermann
150b16ec2c lib/upnp/Discovery: make Upnp_Discovery pointers const 2017-11-16 11:37:04 +01:00
Max Kellermann
c98bc4a243 playlist/PlaylistRegistry: use LockRewind() instead of Rewind()
Fixes a deadlock caused by commit
31ab78ae8e.  That commit was not
actually bad - just these two calls have always been bad, which went
unnoticed for a long time.
2017-11-14 21:19:22 +01:00
Max Kellermann
014f8cd693 output/httpd: flush encoder after tag
Without the flush, ReadPage() may not return any data, or not all
data.  This may result in incomplete ddata the new "header" page,
corrupting streams with some encoders such as Vorbis.

Fixes 
2017-11-14 12:00:14 +01:00
Max Kellermann
aea37e46e3 encoder/vorbis: default to quality 3
Don't require a quality or bitrate setting.  If nothing is set, don't
fail startup - just go with a good default.  A quality setting of 3 is
what "oggenc" defaults to as well.
2017-11-14 11:30:28 +01:00
Max Kellermann
31ab78ae8e input/{cdio,ffmpeg,file,smbclient}: unlock the mutex during blocking I/O
InputStream::Read() and InputStream::Seek() are called with the mutex
locked.  That means the implementation must not block, or unlock the
mutex before calling into blocking code.

Previously, a slow CD drive could stall the whole MPD process,
including the main thread, due to this problem.

Closes 
2017-11-13 17:13:10 +01:00
Max Kellermann
f82e1453e4 input/smbclient: use std::lock_guard 2017-11-13 17:13:10 +01:00
Max Kellermann
a2b77c8813 decoder/ffmpeg, test/test_protocol: catch exceptions by reference
Work around -Werror=catch-value.
2017-11-12 18:54:29 +01:00
Max Kellermann
18add29472 configure.ac: disable -Wnoexcept-type
Workaround for .
2017-11-12 18:54:29 +01:00
cathugger
b111a8fe8d output/Thread: ensure pending tags are flushed in all cases
Fixes hanging playback with soxr resampler.

Closes , 
2017-11-05 17:42:32 +01:00
Marcin Jurkowski
3b23cf0258 decoder/vorbis: scale and clip tremor-decoded samples to 15 bits
Tremor decoder is unusable since commit 2ee43c4. Sound is distorted to
the point where it's nothing but noise.

The data from vorbis_synthesis_pcmout() needs to be scaled and
clipped for 16 bit sample size. For reference see
http://lists.xiph.org/pipermail/tremor/2010-April/001642.html and
http://lists.xiph.org/pipermail/vorbis/2006-October/026513.html.

Signed-off-by: Marcin Jurkowski <marcin1j@gmail.com>
2017-11-03 19:45:41 +01:00
Max Kellermann
28e864e096 player/Thread: log message when decoder is too slow 2017-10-25 20:26:09 +02:00
Max Kellermann
1de19b921a input/curl: call StartRequest() after setting CURLOPT_RANGE
It's not possible to set CURL options after curl_easy_perform(), and
thus the CURLOPT_RANGE had no effect.
2017-10-24 21:43:39 +02:00
Max Kellermann
ff162b5a03 input/curl: move code to StartRequest() 2017-10-24 21:41:17 +02:00
Max Kellermann
d8e4705dd4 input/curl: move the range buffer to the stack
From the CURLOPT_RANGE documentation: "The application does not have
to keep the string around after setting this option."
2017-10-24 21:38:35 +02:00
Max Kellermann
338e1f5926 increment version number to 0.20.12 2017-10-24 17:31:55 +02:00
135 changed files with 790 additions and 323 deletions
Makefile.amNEWS
android
configure.ac
doc
python/build
src
CommandLine.cxxLocateUri.hxxLogBackend.cxxLogInit.cxxLogLevel.hxxMain.cxxMain.hxxMusicChunk.hxxStateFile.cxxStateFile.hxxStats.cxxTimePrint.cxx
client
command
config
db
decoder
encoder
event
fs
input
lib
mixer
net
output
pcm
player
playlist
queue
storage
system
tag
thread
unix
util
win32
test

@@ -243,6 +243,7 @@ CURL_SOURCES = \
src/lib/curl/Slist.hxx
UPNP_SOURCES = \
src/lib/upnp/Compat.hxx \
src/lib/upnp/Init.cxx src/lib/upnp/Init.hxx \
src/lib/upnp/ClientInit.cxx src/lib/upnp/ClientInit.hxx \
src/lib/upnp/Device.cxx src/lib/upnp/Device.hxx \
@@ -701,6 +702,7 @@ libstorage_a_SOURCES = \
src/storage/MemoryDirectoryReader.cxx src/storage/MemoryDirectoryReader.hxx \
src/storage/Configured.cxx src/storage/Configured.hxx \
src/storage/plugins/LocalStorage.cxx src/storage/plugins/LocalStorage.hxx \
src/storage/StorageState.cxx src/storage/StorageState.hxx \
src/storage/FileInfo.hxx
libstorage_a_CPPFLAGS = $(AM_CPPFLAGS) \
@@ -753,6 +755,7 @@ libneighbor_a_SOURCES = \
src/neighbor/NeighborPlugin.hxx
libneighbor_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(UPNP_CFLAGS) \
$(SMBCLIENT_CFLAGS)
if ENABLE_SMBCLIENT
@@ -802,6 +805,8 @@ libdb_plugins_a_SOURCES = \
src/db/plugins/simple/PrefixedLightSong.hxx \
src/db/plugins/simple/SimpleDatabasePlugin.cxx \
src/db/plugins/simple/SimpleDatabasePlugin.hxx
libdb_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(UPNP_CFLAGS)
if ENABLE_LIBMPDCLIENT
libdb_plugins_a_SOURCES += \
@@ -2411,6 +2416,7 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
$(man_MANS) $(DOCBOOK_FILES) doc/mpdconf.example doc/doxygen.conf \
$(wildcard $(srcdir)/doc/include/*.xml) \
systemd/system/mpd.socket \
$(wildcard $(srcdir)/python/build/*.py) \
android/AndroidManifest.xml \
android/build.py \
android/custom_rules.xml \
@@ -2418,5 +2424,6 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
android/src/Bridge.java \
android/src/Loader.java \
android/src/Main.java \
win32/build.py \
win32/res/mpd.rc.in win32/res/mpd.ico \
src/haiku/App_MusicPD

33
NEWS

@@ -1,3 +1,36 @@
ver 0.20.13 (2017/12/18)
* output
- osx: set up ring buffer to hold at least 100ms
* mixer
- alsa: fix rounding errors
* database
- simple: don't purge mount points on update/rescan
- simple: fix "mount" bug caused by bad compiler optimization
- simple: fix "lsinfo" into mount points
- upnp: work around libupnp 1.6.24 API breakage
* queue: fix spuriously misplaced prioritized songs
* save and restore mountpoints within the state file
* include Windows cross-build script in source tarball
* fix Windows build failures
ver 0.20.12 (2017/11/25)
* database
- upnp: adapt to libupnp 1.8 API changes
* input
- cdio_paranoia, ffmpeg, file, smbclient: reduce lock contention,
fixing lots of xrun problems
- curl: fix seeking
* decoder
- ffmpeg: fix GCC 8 warning
- vorbis: fix Tremor support
* player
- log message when decoder is too slow
* encoder
- vorbis: default to quality 3
* output
- fix hanging playback with soxr resampler
- httpd: flush encoder after tag; fixes corrupt Vorbis stream
ver 0.20.11 (2017/10/18)
* storage
- curl: support Content-Type application/xml

@@ -46,13 +46,14 @@ class AndroidNdkToolchain:
self.ndk_arch = 'arm'
android_abi = 'armeabi-v7a'
ndk_platform = 'android-14'
ndk_platform = 'android-21'
# select the NDK compiler
gcc_version = '4.9'
ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform)
sysroot = os.path.join(ndk_platform_path, 'arch-' + self.ndk_arch)
sysroot = os.path.join(ndk_path, 'sysroot')
target_root = os.path.join(ndk_platform_path, 'arch-' + self.ndk_arch)
install_prefix = os.path.join(arch_path, 'root')
@@ -79,8 +80,15 @@ class AndroidNdkToolchain:
self.cflags = '-Os -g ' + common_flags
self.cxxflags = '-Os -g ' + common_flags
self.cppflags = '--sysroot=' + self.sysroot + ' -isystem ' + os.path.join(install_prefix, 'include')
self.ldflags = '--sysroot=' + self.sysroot + ' ' + common_flags + ' -L' + os.path.join(install_prefix, 'lib')
self.cppflags = '--sysroot=' + sysroot + \
' -isystem ' + os.path.join(install_prefix, 'include') + \
' -isystem ' + os.path.join(sysroot, 'usr', 'include', arch) + \
' -D__ANDROID_API__=21'
self.ldflags = '--sysroot=' + sysroot + \
' -L' + os.path.join(install_prefix, 'lib') + \
' -L' + os.path.join(target_root, 'usr', 'lib') + \
' -B' + os.path.join(target_root, 'usr', 'lib') + \
' ' + common_flags
self.libs = ''
self.is_arm = self.ndk_arch == 'arm'

@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.20.11, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.20.13, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=20
VERSION_REVISION=11
VERSION_REVISION=13
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -492,7 +492,7 @@ if test x$enable_ipv6 = xyes; then
AC_EGREP_CPP([AP_maGiC_VALUE],
[
#include <sys/types.h>
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
@@ -1385,6 +1385,11 @@ then
AX_APPEND_COMPILE_FLAGS([-Wcast-qual])
AX_APPEND_COMPILE_FLAGS([-Wwrite-strings])
AX_APPEND_COMPILE_FLAGS([-Wsign-compare])
dnl This GCC8 warning for C++17 ABI compatibility is of no
dnl interest for us, because we're not a shared library.
AX_APPEND_COMPILE_FLAGS([-Wno-noexcept-type])
AC_LANG_POP
fi

@@ -3068,8 +3068,8 @@ run</programlisting>
</entry>
<entry>
Sets the quality for VBR. -1 is the lowest quality,
10 is the highest quality. Cannot be used with
<varname>bitrate</varname>.
10 is the highest quality. Defaults to 3. Cannot
be used with <varname>bitrate</varname>.
</entry>
</row>
<row>

@@ -69,8 +69,8 @@ liblame = AutotoolsProject(
)
ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-3.3.3.tar.xz',
'd2a9002cdc6b533b59728827186c044ad02ba64841f1b7cd6c21779875453a1e',
'http://ffmpeg.org/releases/ffmpeg-3.4.1.tar.xz',
'5a77278a63741efa74e26bf197b9bb09ac6381b9757391b922407210f0f991c0',
'lib/libavcodec.a',
[
'--disable-shared', '--enable-static',
@@ -84,17 +84,26 @@ ffmpeg = FfmpegProject(
'--disable-swscale',
'--disable-postproc',
'--disable-avfilter',
'--disable-lzo',
'--disable-faan',
'--disable-pixelutils',
'--disable-network',
'--disable-encoders',
'--disable-protocols',
'--disable-outdevs',
'--disable-devices',
'--disable-filters',
'--disable-v4l2_m2m',
# clang misinterprets the "B0" in hevc_mvs.c as binary
# literal, which breaks the build; but we don't need that
# video codec anyway
'--disable-decoder=hevc',
],
)
curl = AutotoolsProject(
'http://curl.haxx.se/download/curl-7.55.1.tar.xz',
'3eafca6e84ecb4af5f35795dee84e643d5428287e88c041122bb8dac18676bb7',
'http://curl.haxx.se/download/curl-7.57.0.tar.xz',
'f5f6fd3c72b7b8389969f4fb671ed8532fa9b5bb7a5cae7ca89bc1cea45c7878',
'lib/libcurl.a',
[
'--disable-shared', '--enable-static',
@@ -114,7 +123,7 @@ curl = AutotoolsProject(
)
boost = BoostProject(
'http://downloads.sourceforge.net/project/boost/boost/1.65.0/boost_1_65_0.tar.bz2',
'ea26712742e2fb079c2a566a31f3266973b76e38222b9f88b387e3c8b2f9902c',
'http://downloads.sourceforge.net/project/boost/boost/1.65.1/boost_1_65_1.tar.bz2',
'9807a5d16566c57fd74fb522764e0b134a8bbe6b6e8967b83afefd30dcd3be81',
'include/boost/version.hpp',
)

@@ -67,7 +67,7 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#ifdef _WIN32
#define CONFIG_FILE_LOCATION PATH_LITERAL("mpd\\mpd.conf")
#define APP_CONFIG_FILE_LOCATION PATH_LITERAL("conf\\mpd.conf")
#else
@@ -389,7 +389,7 @@ ParseCommandLine(int argc, char **argv, struct options *options)
ConfigLoader loader;
bool found =
#ifdef WIN32
#ifdef _WIN32
loader.TryFile(GetUserConfigDir(), CONFIG_FILE_LOCATION) ||
loader.TryFile(GetSystemConfigDir(), CONFIG_FILE_LOCATION) ||
loader.TryFile(GetAppBaseDir(), APP_CONFIG_FILE_LOCATION);

@@ -24,7 +24,7 @@
#include "Compiler.h"
#include "fs/AllocatedPath.hxx"
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
/* damn you, windows.h! */
#ifdef ABSOLUTE

@@ -162,7 +162,7 @@ FileLog(const Domain &domain, const char *message)
domain.GetName(),
chomp_length(message), message);
#ifdef WIN32
#ifdef _WIN32
/* force-flush the log file, because setvbuf() does not seem
to have an effect on WIN32 */
fflush(stderr);

@@ -72,7 +72,7 @@ log_init_file(int line)
out_fd = open_log_file();
if (out_fd < 0) {
#ifdef WIN32
#ifdef _WIN32
const std::string out_path_utf8 = out_path.ToUTF8();
throw FormatRuntimeError("failed to open log file \"%s\" (config line %d)",
out_path_utf8.c_str(), line);
@@ -182,7 +182,7 @@ void setup_log_output()
fflush(nullptr);
if (out_fd < 0) {
#ifdef WIN32
#ifdef _WIN32
return;
#else
out_fd = open("/dev/null", O_WRONLY);

@@ -20,7 +20,7 @@
#ifndef MPD_LOG_LEVEL_HXX
#define MPD_LOG_LEVEL_HXX
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
/* damn you, windows.h! */
#ifdef ERROR

@@ -106,7 +106,7 @@
#include <locale.h>
#endif
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
@@ -289,7 +289,7 @@ glue_state_file_init()
*/
static void winsock_init(void)
{
#ifdef WIN32
#ifdef _WIN32
WSADATA sockinfo;
int retval = WSAStartup(MAKEWORD(2, 2), &sockinfo);
@@ -418,7 +418,7 @@ Instance::OnIdle(unsigned flags)
int main(int argc, char *argv[])
{
#ifdef WIN32
#ifdef _WIN32
return win32_main(argc, argv);
#else
return mpd_main(argc, argv);
@@ -615,7 +615,7 @@ try {
playlist_state_restore() */
instance->partition->pc.LockUpdateAudio();
#ifdef WIN32
#ifdef _WIN32
win32_app_started();
#endif
@@ -630,7 +630,7 @@ try {
/* run the main loop */
instance->event_loop.Run();
#ifdef WIN32
#ifdef _WIN32
win32_app_stopping();
#endif
@@ -702,7 +702,7 @@ try {
daemonize_finish();
#endif
#ifdef WIN32
#ifdef _WIN32
WSACleanup();
#endif

@@ -42,7 +42,7 @@ int mpd_main(int argc, char *argv[]);
#endif
#ifdef WIN32
#ifdef _WIN32
/**
* If program is run as windows service performs nessesary initialization

@@ -79,12 +79,20 @@ struct MusicChunk {
*/
ReplayGainInfo replay_gain_info;
/**
* A magic value for #replay_gain_serial which omits updating
* the #ReplayGainFilter. This is used by "silence" chunks
* (see PlayerThread::SendSilence()) so they don't affect the
* replay gain.
*/
static constexpr unsigned IGNORE_REPLAY_GAIN = ~0u;
/**
* A serial number for checking if replay gain info has
* changed since the last chunk. The magic value 0 indicates
* that there is no replay gain info available.
*/
unsigned replay_gain_serial = 0;
unsigned replay_gain_serial;
/** the data (probably PCM) */
uint8_t data[CHUNK_SIZE];

@@ -24,6 +24,7 @@
#include "fs/io/TextFile.hxx"
#include "fs/io/FileOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "storage/StorageState.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "mixer/Volume.hxx"
@@ -56,6 +57,9 @@ StateFile::RememberVersions() noexcept
prev_output_version = audio_output_state_get_version();
prev_playlist_version = playlist_state_get_hash(partition.playlist,
partition.pc);
#ifdef ENABLE_DATABASE
prev_storage_version = storage_state_get_hash(partition.instance);
#endif
}
bool
@@ -64,7 +68,11 @@ StateFile::IsModified() const noexcept
return prev_volume_version != sw_volume_state_get_hash() ||
prev_output_version != audio_output_state_get_version() ||
prev_playlist_version != playlist_state_get_hash(partition.playlist,
partition.pc);
partition.pc)
#ifdef ENABLE_DATABASE
|| prev_storage_version != storage_state_get_hash(partition.instance)
#endif
;
}
inline void
@@ -72,6 +80,11 @@ StateFile::Write(BufferedOutputStream &os)
{
save_sw_volume_state(os);
audio_output_state_save(os, partition.outputs);
#ifdef ENABLE_DATABASE
storage_state_save(os, partition.instance);
#endif
playlist_state_save(os, partition.playlist, partition.pc);
}
@@ -123,6 +136,10 @@ try {
playlist_state_restore(line, file, song_loader,
partition.playlist,
partition.pc);
#ifdef ENABLE_DATABASE
success = success || storage_state_restore(line, file, partition.instance);
#endif
if (!success)
FormatError(state_file_domain,
"Unrecognized line in state file: %s",

@@ -46,6 +46,10 @@ class StateFile final : private TimeoutMonitor {
unsigned prev_volume_version = 0, prev_output_version = 0,
prev_playlist_version = 0;
#ifdef ENABLE_DATABASE
unsigned prev_storage_version = 0;
#endif
public:
static constexpr std::chrono::steady_clock::duration DEFAULT_INTERVAL = std::chrono::minutes(2);

@@ -31,7 +31,7 @@
#include <chrono>
#ifndef WIN32
#ifndef _WIN32
/**
* The monotonic time stamp when MPD was started. It is used to
* calculate the uptime.
@@ -114,7 +114,7 @@ stats_print(Response &r, const Partition &partition)
{
r.Format("uptime: %u\n"
"playtime: %lu\n",
#ifdef WIN32
#ifdef _WIN32
GetProcessUptimeS(),
#else
(unsigned)std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start_time).count(),

@@ -24,7 +24,7 @@
void
time_print(Response &r, const char *name, time_t t)
{
#ifdef WIN32
#ifdef _WIN32
const struct tm *tm2 = gmtime(&t);
#else
struct tm tm;
@@ -35,7 +35,7 @@ time_print(Response &r, const char *name, time_t t)
char buffer[32];
strftime(buffer, sizeof(buffer),
#ifdef WIN32
#ifdef _WIN32
"%Y-%m-%dT%H:%M:%SZ",
#else
"%FT%TZ",

@@ -28,7 +28,7 @@
void
Client::AllowFile(Path path_fs) const
{
#ifdef WIN32
#ifdef _WIN32
(void)path_fs;
throw ProtocolError(ACK_ERROR_PERMISSION, "Access denied");

@@ -24,7 +24,7 @@
#include <string>
#ifdef WIN32
#ifdef _WIN32
/* fuck WIN32! */
#include <windows.h>
#undef GetMessage

@@ -29,7 +29,7 @@
#include "Log.hxx"
#include <assert.h>
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>

@@ -20,7 +20,7 @@
#ifndef MPD_COMMAND_RESULT_HXX
#define MPD_COMMAND_RESULT_HXX
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
/* damn you, windows.h! */
#ifdef ERROR

@@ -58,7 +58,7 @@ skip_path(Path name_fs) noexcept
return name_fs.HasNewline();
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
/* PRIu64 causes bogus compiler warning */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
@@ -101,7 +101,7 @@ handle_listfiles_local(Response &r, Path path_fs)
return CommandResult::OK;
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop
#endif

@@ -50,7 +50,7 @@ skip_path(const char *name_utf8) noexcept
return strchr(name_utf8, '\n') != nullptr;
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
/* PRIu64 causes bogus compiler warning */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
@@ -94,7 +94,7 @@ handle_listfiles_storage(Response &r, StorageDirectoryReader &reader)
}
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop
#endif

@@ -22,7 +22,7 @@
#include "Compiler.h"
#if defined(WIN32) && CLANG_OR_GCC_VERSION(4,7)
#if defined(_WIN32) && CLANG_OR_GCC_VERSION(4,7)
/* "INPUT" is declared by winuser.h */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
@@ -93,7 +93,7 @@ enum class ConfigBlockOption {
MAX
};
#if defined(WIN32) && CLANG_OR_GCC_VERSION(4,7)
#if defined(_WIN32) && CLANG_OR_GCC_VERSION(4,7)
#pragma GCC diagnostic pop
#endif

@@ -29,7 +29,7 @@
#include <assert.h>
#include <string.h>
#ifndef WIN32
#ifndef _WIN32
#include <pwd.h>
/**
@@ -79,7 +79,7 @@ ParsePath(const char *path)
{
assert(path != nullptr);
#ifndef WIN32
#ifndef _WIN32
if (path[0] == '~') {
++path;
@@ -119,7 +119,7 @@ ParsePath(const char *path)
} else {
#endif
return AllocatedPath::FromUTF8Throw(path);
#ifndef WIN32
#ifndef _WIN32
}
#endif
}

@@ -109,7 +109,7 @@ Directory::PruneEmpty() noexcept
child != end;) {
child->PruneEmpty();
if (child->IsEmpty())
if (child->IsEmpty() && !child->IsMount())
child = children.erase_and_dispose(child,
DeleteDisposer());
else
@@ -230,7 +230,7 @@ Directory::Walk(bool recursive, const SongFilter *filter,
call will lock it again */
const ScopeDatabaseUnlock unlock;
WalkMount(GetPath(), *mounted_database,
recursive, filter,
"", recursive, filter,
visit_directory, visit_song,
visit_playlist);
return;

@@ -127,7 +127,6 @@ public:
*
* @param name_utf8 the UTF-8 encoded name of the new sub directory
*/
gcc_malloc
Directory *CreateChild(const char *name_utf8);
/**

@@ -72,7 +72,7 @@ PrefixVisitPlaylist(const char *base, const VisitPlaylist &visit_playlist,
void
WalkMount(const char *base, const Database &db,
bool recursive, const SongFilter *filter,
const char* uri, bool recursive, const SongFilter *filter,
const VisitDirectory &visit_directory, const VisitSong &visit_song,
const VisitPlaylist &visit_playlist)
{
@@ -93,5 +93,5 @@ WalkMount(const char *base, const Database &db,
vp = std::bind(PrefixVisitPlaylist,
base, std::ref(visit_playlist), _1, _2);
db.Visit(DatabaseSelection("", recursive, filter), vd, vs, vp);
db.Visit(DatabaseSelection(uri, recursive, filter), vd, vs, vp);
}

@@ -27,7 +27,7 @@ class SongFilter;
void
WalkMount(const char *base, const Database &db,
bool recursive, const SongFilter *filter,
const char* uri, bool recursive, const SongFilter *filter,
const VisitDirectory &visit_directory, const VisitSong &visit_song,
const VisitPlaylist &visit_playlist);

@@ -20,6 +20,7 @@
#include "config.h"
#include "SimpleDatabasePlugin.hxx"
#include "PrefixedLightSong.hxx"
#include "Mount.hxx"
#include "db/DatabasePlugin.hxx"
#include "db/Selection.hxx"
#include "db/Helpers.hxx"
@@ -115,7 +116,7 @@ SimpleDatabase::Check() const
path_utf8 + "\" because the "
"parent path is not a directory");
#ifndef WIN32
#ifndef _WIN32
/* Check if we can write to the directory */
if (!CheckAccess(dirPath, X_OK | W_OK)) {
const int e = errno;
@@ -134,7 +135,7 @@ SimpleDatabase::Check() const
if (!fi.IsRegular())
throw std::runtime_error("db file \"" + path_utf8 + "\" is not a regular file");
#ifndef WIN32
#ifndef _WIN32
/* And check that we can write to it */
if (!CheckAccess(path, R_OK | W_OK))
throw FormatErrno("Can't open db file \"%s\" for reading/writing",
@@ -270,6 +271,18 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
ScopeDatabaseLock protect;
auto r = root->LookupDirectory(selection.uri.c_str());
if (r.directory->IsMount()) {
/* pass the request and the remaining uri to the mounted database */
protect.unlock();
WalkMount(r.directory->GetPath(), *(r.directory->mounted_database),
(r.uri == nullptr)?"":r.uri, selection.recursive, selection.filter,
visit_directory, visit_song, visit_playlist);
return;
}
if (r.uri == nullptr) {
/* it's a directory */

@@ -91,7 +91,7 @@ bool
directory_child_access(Storage &storage, const Directory &directory,
const char *name, int mode) noexcept
{
#ifdef WIN32
#ifdef _WIN32
/* CheckAccess() is useless on WIN32 */
(void)storage;
(void)directory;

@@ -55,7 +55,7 @@ UpdateWalk::UpdateWalk(EventLoop &_loop, DatabaseListener &_listener,
storage(_storage),
editor(_loop, _listener)
{
#ifndef WIN32
#ifndef _WIN32
follow_inside_symlinks =
config_get_bool(ConfigOption::FOLLOW_INSIDE_SYMLINKS,
DEFAULT_FOLLOW_INSIDE_SYMLINKS);
@@ -104,7 +104,7 @@ inline void
UpdateWalk::PurgeDeletedFromDirectory(Directory &directory)
{
directory.ForEachChildSafe([&](Directory &child){
if (DirectoryExists(storage, child))
if (child.IsMount() || DirectoryExists(storage, child))
return;
editor.LockDeleteDirectory(&child);
@@ -133,7 +133,7 @@ UpdateWalk::PurgeDeletedFromDirectory(Directory &directory)
}
}
#ifndef WIN32
#ifndef _WIN32
static bool
update_directory_stat(Storage &storage, Directory &directory)
{
@@ -156,7 +156,7 @@ static int
FindAncestorLoop(Storage &storage, Directory *parent,
unsigned inode, unsigned device)
{
#ifndef WIN32
#ifndef _WIN32
if (device == 0 && inode == 0)
/* can't detect loops if the Storage does not support
these numbers */
@@ -258,7 +258,7 @@ bool
UpdateWalk::SkipSymlink(const Directory *directory,
const char *utf8_name) const noexcept
{
#ifndef WIN32
#ifndef _WIN32
const auto path_fs = storage.MapChildFS(directory->GetPath(),
utf8_name);
if (path_fs.IsNull())

@@ -36,7 +36,7 @@ class UpdateWalk final {
friend class UpdateArchiveVisitor;
#endif
#ifndef WIN32
#ifndef _WIN32
static constexpr bool DEFAULT_FOLLOW_INSIDE_SYMLINKS = true;
static constexpr bool DEFAULT_FOLLOW_OUTSIDE_SYMLINKS = true;

@@ -258,7 +258,7 @@ FfmpegSendFrame(DecoderClient &client, InputStream &is,
try {
output_buffer = copy_interleave_frame(codec_context, frame,
buffer);
} catch (const std::exception e) {
} catch (const std::exception &e) {
/* this must be a serious error, e.g. OOM */
LogError(e);
return DecoderCommand::STOP;

@@ -46,7 +46,7 @@ FlacIORead(void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
p += nbytes;
#ifndef WIN32
#ifndef _WIN32
} catch (const std::system_error &e) {
errno = e.code().category() == ErrnoCategory()
? e.code().value()

@@ -178,6 +178,20 @@ VorbisDecoder::SubmitInit()
client.Ready(audio_format, eos_granulepos > 0, duration);
}
#ifdef HAVE_TREMOR
static inline int16_t tremor_clip_sample(int32_t x)
{
x >>= 9;
if (x < INT16_MIN)
return INT16_MIN;
if (x > INT16_MAX)
return INT16_MAX;
return x;
}
#endif
bool
VorbisDecoder::SubmitSomePcm()
{
@@ -197,7 +211,7 @@ VorbisDecoder::SubmitSomePcm()
auto *dest = &buffer[c];
for (size_t i = 0; i < n_frames; ++i) {
*dest = *src++;
*dest = tremor_clip_sample(*src++);
dest += channels;
}
}

@@ -62,7 +62,7 @@ private:
};
class PreparedVorbisEncoder final : public PreparedEncoder {
float quality;
float quality = 3;
int bitrate;
public:
@@ -97,7 +97,7 @@ PreparedVorbisEncoder::PreparedVorbisEncoder(const ConfigBlock &block)
value = block.GetBlockValue("bitrate");
if (value == nullptr)
throw std::runtime_error("neither bitrate nor quality defined");
return;
quality = -2.0;

@@ -23,7 +23,7 @@
#include <algorithm>
#ifndef WIN32
#ifndef _WIN32
#include <poll.h>
#endif
@@ -50,7 +50,7 @@ MultiSocketMonitor::ClearSocketList()
fds.clear();
}
#ifndef WIN32
#ifndef _WIN32
void
MultiSocketMonitor::ReplaceSocketList(pollfd *pfds, unsigned n)

@@ -31,7 +31,7 @@
#include <assert.h>
#ifdef WIN32
#ifdef _WIN32
/* ERROR is a WIN32 macro that poisons our namespace; this is a kludge
to allow us to use it anyway */
#ifdef ERROR
@@ -39,7 +39,7 @@
#endif
#endif
#ifndef WIN32
#ifndef _WIN32
struct pollfd;
#endif
@@ -189,7 +189,7 @@ public:
}
}
#ifndef WIN32
#ifndef _WIN32
/**
* Replace the socket list with the given file descriptors.
* The given pollfd array will be modified by this method.

@@ -43,7 +43,7 @@
#include <unistd.h>
#include <assert.h>
#ifdef WIN32
#ifdef _WIN32
#include <ws2tcpip.h>
#include <winsock.h>
#else

@@ -20,7 +20,7 @@
#include "config.h"
#include "SignalMonitor.hxx"
#ifndef WIN32
#ifndef _WIN32
#include "SocketMonitor.hxx"
#include "util/Manual.hxx"

@@ -24,7 +24,7 @@
class EventLoop;
#ifndef WIN32
#ifndef _WIN32
#include "util/BindMethod.hxx"

@@ -24,7 +24,7 @@
#include <assert.h>
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>

@@ -28,7 +28,7 @@
#include <assert.h>
#include <stddef.h>
#ifdef WIN32
#ifdef _WIN32
/* ERROR is a WIN32 macro that poisons our namespace; this is a kludge
to allow us to use it anyway */
#ifdef ERROR

@@ -31,7 +31,7 @@ AllocatedPath::~AllocatedPath() {}
AllocatedPath
AllocatedPath::FromUTF8(const char *path_utf8) noexcept
{
#if defined(HAVE_FS_CHARSET) || defined(WIN32)
#if defined(HAVE_FS_CHARSET) || defined(_WIN32)
try {
return AllocatedPath(::PathFromUTF8(path_utf8));
} catch (const std::runtime_error &) {
@@ -45,7 +45,7 @@ AllocatedPath::FromUTF8(const char *path_utf8) noexcept
AllocatedPath
AllocatedPath::FromUTF8Throw(const char *path_utf8)
{
#if defined(HAVE_FS_CHARSET) || defined(WIN32)
#if defined(HAVE_FS_CHARSET) || defined(_WIN32)
return AllocatedPath(::PathFromUTF8(path_utf8));
#else
return FromFS(path_utf8);

@@ -24,7 +24,7 @@
#include "lib/icu/Converter.hxx"
#include "util/AllocatedString.hxx"
#ifdef WIN32
#ifdef _WIN32
#include "lib/icu/Win32.hxx"
#include <windows.h>
#endif
@@ -70,7 +70,7 @@ GetFSCharset() noexcept
{
#ifdef HAVE_FS_CHARSET
return fs_charset.empty() ? "UTF-8" : fs_charset.c_str();
#elif defined(WIN32)
#elif defined(_WIN32)
return "ACP";
#else
return "UTF-8";
@@ -100,7 +100,7 @@ PathToUTF8(PathTraitsFS::const_pointer_type path_fs)
assert(path_fs != nullptr);
#endif
#ifdef WIN32
#ifdef _WIN32
const auto buffer = WideCharToMultiByte(CP_UTF8, path_fs);
return FixSeparators(PathTraitsUTF8::string(buffer.c_str()));
#else
@@ -116,7 +116,7 @@ PathToUTF8(PathTraitsFS::const_pointer_type path_fs)
#endif
}
#if defined(HAVE_FS_CHARSET) || defined(WIN32)
#if defined(HAVE_FS_CHARSET) || defined(_WIN32)
PathTraitsFS::string
PathFromUTF8(PathTraitsUTF8::const_pointer_type path_utf8)
@@ -126,7 +126,7 @@ PathFromUTF8(PathTraitsUTF8::const_pointer_type path_utf8)
assert(path_utf8 != nullptr);
#endif
#ifdef WIN32
#ifdef _WIN32
const auto buffer = MultiByteToWideChar(CP_UTF8, path_utf8);
return PathTraitsFS::string(buffer.c_str());
#else

@@ -24,7 +24,7 @@
#include "Compiler.h"
#include "Traits.hxx"
#if (defined(HAVE_ICU) || defined(HAVE_ICONV)) && !defined(WIN32)
#if (defined(HAVE_ICU) || defined(HAVE_ICONV)) && !defined(_WIN32)
#define HAVE_FS_CHARSET
#endif

@@ -41,7 +41,7 @@ try {
return;
}
#ifndef WIN32
#ifndef _WIN32
try {
const auto x = AllocatedPath::Build(path_fs,
PathTraitsFS::CURRENT_DIRECTORY);

@@ -21,7 +21,7 @@
#include "DirectoryReader.hxx"
#include "system/Error.hxx"
#ifdef WIN32
#ifdef _WIN32
DirectoryReader::DirectoryReader(Path dir)
:handle(FindFirstFile(MakeWildcardPath(dir.c_str()), &data))

@@ -23,7 +23,7 @@
#include "check.h"
#include "Path.hxx"
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>

@@ -26,13 +26,13 @@
#include <stdint.h>
#ifdef WIN32
#ifdef _WIN32
#include <fileapi.h>
#else
#include <sys/stat.h>
#endif
#ifdef WIN32
#ifdef _WIN32
static inline constexpr uint64_t
ConstructUint64(DWORD lo, DWORD hi)
@@ -54,7 +54,7 @@ class FileInfo {
bool follow_symlinks);
friend class FileReader;
#ifdef WIN32
#ifdef _WIN32
WIN32_FILE_ATTRIBUTE_DATA data;
#else
struct stat st;
@@ -65,7 +65,7 @@ public:
FileInfo(Path path, bool follow_symlinks=true) {
if (!GetFileInfo(path, *this, follow_symlinks)) {
#ifdef WIN32
#ifdef _WIN32
throw FormatLastError("Failed to access %s",
path.ToUTF8().c_str());
#else
@@ -76,7 +76,7 @@ public:
}
bool IsRegular() const {
#ifdef WIN32
#ifdef _WIN32
return (data.dwFileAttributes &
(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)) == 0;
#else
@@ -85,7 +85,7 @@ public:
}
bool IsDirectory() const {
#ifdef WIN32
#ifdef _WIN32
return data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
#else
return S_ISDIR(st.st_mode);
@@ -93,7 +93,7 @@ public:
}
uint64_t GetSize() const {
#ifdef WIN32
#ifdef _WIN32
return ConstructUint64(data.nFileSizeLow, data.nFileSizeHigh);
#else
return st.st_size;
@@ -101,14 +101,14 @@ public:
}
time_t GetModificationTime() const {
#ifdef WIN32
#ifdef _WIN32
return FileTimeToTimeT(data.ftLastWriteTime);
#else
return st.st_mtime;
#endif
}
#ifndef WIN32
#ifndef _WIN32
uid_t GetUid() const {
return st.st_uid;
}
@@ -130,7 +130,7 @@ public:
inline bool
GetFileInfo(Path path, FileInfo &info, bool follow_symlinks=true)
{
#ifdef WIN32
#ifdef _WIN32
(void)follow_symlinks;
return GetFileAttributesEx(path.c_str(), GetFileExInfoStandard,
&info.data);

@@ -29,7 +29,7 @@
void
RenameFile(Path oldpath, Path newpath)
{
#ifdef WIN32
#ifdef _WIN32
if (!MoveFileEx(oldpath.c_str(), newpath.c_str(),
MOVEFILE_REPLACE_EXISTING))
throw MakeLastError("Failed to rename file");
@@ -42,7 +42,7 @@ RenameFile(Path oldpath, Path newpath)
AllocatedPath
ReadLink(Path path)
{
#ifdef WIN32
#ifdef _WIN32
(void)path;
errno = EINVAL;
return AllocatedPath::Null();
@@ -63,7 +63,7 @@ ReadLink(Path path)
void
TruncateFile(Path path)
{
#ifdef WIN32
#ifdef _WIN32
HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, nullptr,
TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr);
@@ -83,7 +83,7 @@ TruncateFile(Path path)
void
RemoveFile(Path path)
{
#ifdef WIN32
#ifdef _WIN32
if (!DeleteFile(path.c_str()))
throw FormatLastError("Failed to delete %s", path.c_str());
#else

@@ -26,7 +26,7 @@
#include "Path.hxx"
#ifdef WIN32
#ifdef _WIN32
#include <fileapi.h>
#endif
@@ -43,7 +43,7 @@ class AllocatedPath;
static inline FILE *
FOpen(Path file, PathTraitsFS::const_pointer_type mode)
{
#ifdef WIN32
#ifdef _WIN32
return _tfopen(file.c_str(), mode);
#else
return fopen(file.c_str(), mode);
@@ -56,7 +56,7 @@ FOpen(Path file, PathTraitsFS::const_pointer_type mode)
static inline int
OpenFile(Path file, int flags, int mode)
{
#ifdef WIN32
#ifdef _WIN32
return _topen(file.c_str(), flags, mode);
#else
return open_cloexec(file.c_str(), flags, mode);
@@ -71,7 +71,7 @@ OpenFile(Path file, int flags, int mode)
void
RenameFile(Path oldpath, Path newpath);
#ifndef WIN32
#ifndef _WIN32
/**
* Wrapper for stat() that uses #Path names.
@@ -107,7 +107,7 @@ RemoveFile(Path path);
AllocatedPath
ReadLink(Path path);
#ifndef WIN32
#ifndef _WIN32
static inline bool
MakeFifo(Path path, mode_t mode)
@@ -132,7 +132,7 @@ CheckAccess(Path path, int mode)
static inline bool
FileExists(Path path, bool follow_symlinks = true)
{
#ifdef WIN32
#ifdef _WIN32
(void)follow_symlinks;
const auto a = GetFileAttributes(path.c_str());
@@ -150,7 +150,7 @@ FileExists(Path path, bool follow_symlinks = true)
static inline bool
DirectoryExists(Path path, bool follow_symlinks = true)
{
#ifdef WIN32
#ifdef _WIN32
(void)follow_symlinks;
const auto a = GetFileAttributes(path.c_str());
@@ -167,7 +167,7 @@ DirectoryExists(Path path, bool follow_symlinks = true)
static inline bool
PathExists(Path path)
{
#ifdef WIN32
#ifdef _WIN32
return GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES;
#else
return CheckAccess(path, F_OK);

@@ -26,7 +26,7 @@
#define HAVE_CLASS_GLOB
#include <string>
#include <fnmatch.h>
#elif defined(WIN32)
#elif defined(_WIN32)
#define HAVE_CLASS_GLOB
#include <string>
#include <shlwapi.h>
@@ -40,12 +40,12 @@
* (asterisk and question mark).
*/
class Glob {
#if defined(HAVE_FNMATCH) || defined(WIN32)
#if defined(HAVE_FNMATCH) || defined(_WIN32)
std::string pattern;
#endif
public:
#if defined(HAVE_FNMATCH) || defined(WIN32)
#if defined(HAVE_FNMATCH) || defined(_WIN32)
explicit Glob(const char *_pattern)
:pattern(_pattern) {}
@@ -57,7 +57,7 @@ public:
bool Check(const char *name_fs) const noexcept {
#ifdef HAVE_FNMATCH
return fnmatch(pattern.c_str(), name_fs, 0) == 0;
#elif defined(WIN32)
#elif defined(_WIN32)
return PathMatchSpecA(name_fs, pattern.c_str());
#endif
}

@@ -25,7 +25,7 @@
#include <stddef.h>
#include <limits.h>
#if defined(WIN32)
#if defined(_WIN32)
static constexpr size_t MPD_PATH_MAX = 260;
#elif defined(MAXPATHLEN)
static constexpr size_t MPD_PATH_MAX = MAXPATHLEN;

@@ -20,7 +20,7 @@
#include "config.h"
// Use X Desktop guidelines where applicable
#if !defined(__APPLE__) && !defined(WIN32) && !defined(ANDROID)
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(ANDROID)
#define USE_XDG
#endif
@@ -29,7 +29,7 @@
#include <array>
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
#else
@@ -53,7 +53,7 @@
#include "Main.hxx"
#endif
#if !defined(WIN32) && !defined(ANDROID)
#if !defined(_WIN32) && !defined(ANDROID)
class PasswdEntry
{
#if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
@@ -113,7 +113,7 @@ SafePathFromFS(PathTraitsFS::const_pointer_type dir)
}
#endif
#ifdef WIN32
#ifdef _WIN32
static AllocatedPath GetStandardDir(int folder_id)
{
std::array<PathTraitsFS::value_type, MAX_PATH> dir;
@@ -226,7 +226,7 @@ try {
AllocatedPath
GetUserConfigDir() noexcept
{
#if defined(WIN32)
#if defined(_WIN32)
return GetStandardDir(CSIDL_LOCAL_APPDATA);
#elif defined(USE_XDG)
// Check for $XDG_CONFIG_HOME
@@ -251,7 +251,7 @@ GetUserConfigDir() noexcept
AllocatedPath
GetUserMusicDir() noexcept
{
#if defined(WIN32)
#if defined(_WIN32)
return GetStandardDir(CSIDL_MYMUSIC);
#elif defined(USE_XDG)
return GetUserDir("XDG_MUSIC_DIR");
@@ -287,7 +287,7 @@ GetUserCacheDir() noexcept
#endif
}
#ifdef WIN32
#ifdef _WIN32
AllocatedPath
GetSystemConfigDir() noexcept

@@ -42,7 +42,7 @@ gcc_pure
AllocatedPath
GetUserCacheDir() noexcept;
#ifdef WIN32
#ifdef _WIN32
/**
* Obtains system configuration directory.

@@ -78,7 +78,7 @@ GetParentPathImpl(typename Traits::const_pointer_type p)
return typename Traits::string(Traits::CURRENT_DIRECTORY);
if (sep == p)
return typename Traits::string(p, p + 1);
#ifdef WIN32
#ifdef _WIN32
if (Traits::IsDrive(p) && sep == p + 2)
return typename Traits::string(p, p + 3);
#endif

@@ -25,7 +25,7 @@
#include "util/StringPointer.hxx"
#include "util/StringAPI.hxx"
#ifdef WIN32
#ifdef _WIN32
#include "util/CharUtil.hxx"
#include <tchar.h>
#endif
@@ -34,7 +34,7 @@
#include <assert.h>
#ifdef WIN32
#ifdef _WIN32
#define PATH_LITERAL(s) _T(s)
#else
#define PATH_LITERAL(s) (s)
@@ -44,7 +44,7 @@
* This class describes the nature of a native filesystem path.
*/
struct PathTraitsFS {
#ifdef WIN32
#ifdef _WIN32
typedef std::wstring string;
#else
typedef std::string string;
@@ -55,7 +55,7 @@ struct PathTraitsFS {
typedef Pointer::pointer_type pointer_type;
typedef Pointer::const_pointer_type const_pointer_type;
#ifdef WIN32
#ifdef _WIN32
static constexpr value_type SEPARATOR = '\\';
#else
static constexpr value_type SEPARATOR = '/';
@@ -65,7 +65,7 @@ struct PathTraitsFS {
static constexpr bool IsSeparator(value_type ch) noexcept {
return
#ifdef WIN32
#ifdef _WIN32
ch == '/' ||
#endif
ch == SEPARATOR;
@@ -78,7 +78,7 @@ struct PathTraitsFS {
assert(p != nullptr);
#endif
#ifdef WIN32
#ifdef _WIN32
const_pointer_type pos = p + GetLength(p);
while (p != pos && !IsSeparator(*pos))
--pos;
@@ -88,7 +88,7 @@ struct PathTraitsFS {
#endif
}
#ifdef WIN32
#ifdef _WIN32
gcc_pure gcc_nonnull_all
static constexpr bool IsDrive(const_pointer_type p) noexcept {
return IsAlphaASCII(p[0]) && p[1] == ':';
@@ -102,7 +102,7 @@ struct PathTraitsFS {
assert(p != nullptr);
#endif
#ifdef WIN32
#ifdef _WIN32
if (IsDrive(p) && IsSeparator(p[2]))
return true;
#endif
@@ -188,7 +188,7 @@ struct PathTraitsUTF8 {
return strrchr(p, SEPARATOR);
}
#ifdef WIN32
#ifdef _WIN32
gcc_pure gcc_nonnull_all
static constexpr bool IsDrive(const_pointer_type p) noexcept {
return IsAlphaASCII(p[0]) && p[1] == ':';
@@ -202,7 +202,7 @@ struct PathTraitsUTF8 {
assert(p != nullptr);
#endif
#ifdef WIN32
#ifdef _WIN32
if (IsDrive(p) && IsSeparator(p[2]))
return true;
#endif

@@ -43,7 +43,7 @@ FileOutputStream::FileOutputStream(Path _path, Mode _mode)
}
}
#ifdef WIN32
#ifdef _WIN32
inline void
FileOutputStream::OpenCreate(gcc_unused bool visible)
@@ -223,7 +223,7 @@ FileOutputStream::Commit()
#endif
if (!Close()) {
#ifdef WIN32
#ifdef _WIN32
throw FormatLastError("Failed to commit %s",
path.ToUTF8().c_str());
#else

@@ -25,14 +25,14 @@
#include "fs/AllocatedPath.hxx"
#include "Compiler.h"
#ifndef WIN32
#ifndef _WIN32
#include "system/FileDescriptor.hxx"
#endif
#include <assert.h>
#include <stdint.h>
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
#endif
@@ -41,7 +41,7 @@ class Path;
class FileOutputStream final : public OutputStream {
const AllocatedPath path;
#ifdef WIN32
#ifdef _WIN32
HANDLE handle = INVALID_HANDLE_VALUE;
#else
FileDescriptor fd = FileDescriptor::Undefined();
@@ -116,7 +116,7 @@ private:
bool Close() {
assert(IsDefined());
#ifdef WIN32
#ifdef _WIN32
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
return true;
@@ -125,7 +125,7 @@ private:
#endif
}
#ifdef WIN32
#ifdef _WIN32
bool SeekEOF() {
return SetFilePointer(handle, 0, nullptr,
FILE_END) != 0xffffffff;
@@ -133,7 +133,7 @@ private:
#endif
bool IsDefined() const {
#ifdef WIN32
#ifdef _WIN32
return handle != INVALID_HANDLE_VALUE;
#else
return fd.IsDefined();

@@ -24,7 +24,7 @@
#include <assert.h>
#ifdef WIN32
#ifdef _WIN32
FileReader::FileReader(Path _path)
:path(_path),

@@ -25,11 +25,11 @@
#include "fs/AllocatedPath.hxx"
#include "Compiler.h"
#ifndef WIN32
#ifndef _WIN32
#include "system/FileDescriptor.hxx"
#endif
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
#endif
@@ -39,7 +39,7 @@ class FileInfo;
class FileReader final : public Reader {
AllocatedPath path;
#ifdef WIN32
#ifdef _WIN32
HANDLE handle;
#else
FileDescriptor fd;
@@ -48,7 +48,7 @@ class FileReader final : public Reader {
public:
explicit FileReader(Path _path);
#ifdef WIN32
#ifdef _WIN32
FileReader(FileReader &&other)
:path(std::move(other.path)),
handle(other.handle) {
@@ -70,7 +70,7 @@ public:
protected:
bool IsDefined() const {
#ifdef WIN32
#ifdef _WIN32
return handle != INVALID_HANDLE_VALUE;
#else
return fd.IsDefined();
@@ -78,7 +78,7 @@ protected:
}
public:
#ifndef WIN32
#ifndef _WIN32
FileDescriptor GetFD() const {
return fd;
}
@@ -90,7 +90,7 @@ public:
gcc_pure
uint64_t GetSize() const noexcept {
#ifdef WIN32
#ifdef _WIN32
LARGE_INTEGER size;
return GetFileSizeEx(handle, &size)
? size.QuadPart
@@ -102,7 +102,7 @@ public:
gcc_pure
uint64_t GetPosition() const noexcept {
#ifdef WIN32
#ifdef _WIN32
LARGE_INTEGER zero;
zero.QuadPart = 0;
LARGE_INTEGER position;

@@ -26,7 +26,7 @@
#include <stddef.h>
#include <stdint.h>
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
/* damn you, windows.h! */
#ifdef ERROR

@@ -270,7 +270,10 @@ CdioParanoiaInputStream::Seek(offset_type new_offset)
lsn_relofs = new_offset / CDIO_CD_FRAMESIZE_RAW;
offset = new_offset;
cdio_paranoia_seek(para, lsn_from + lsn_relofs, SEEK_SET);
{
const ScopeUnlock unlock(mutex);
cdio_paranoia_seek(para, lsn_from + lsn_relofs, SEEK_SET);
}
}
size_t
@@ -292,6 +295,8 @@ CdioParanoiaInputStream::Read(void *ptr, size_t length)
//current sector was changed ?
if (lsn_relofs != buffer_lsn) {
const ScopeUnlock unlock(mutex);
rbuf = cdio_paranoia_read(para, nullptr);
s_err = cdda_errors(drv);

@@ -64,7 +64,6 @@ static const size_t CURL_RESUME_AT = 384 * 1024;
struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
/* some buffers which were passed to libcurl, which we have
too free */
char range[32];
CurlSlist request_headers;
CurlRequest *request = nullptr;
@@ -86,8 +85,19 @@ struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
static InputStream *Open(const char *url, Mutex &mutex, Cond &cond);
/**
* Create and initialize a new #CurlRequest instance. After
* this, you may add more request headers and set options. To
* actually start the request, call StartRequest().
*/
void InitEasy();
/**
* Start the request after having called InitEasy(). After
* this, you must not set any CURL options.
*/
void StartRequest();
/**
* Frees the current "libcurl easy" handle, and everything
* associated with it.
@@ -217,7 +227,7 @@ CurlInputStream::OnHeaders(unsigned status,
if (i != headers.end()) {
size_t icy_metaint = ParseUint64(i->second.c_str());
#ifndef WIN32
#ifndef _WIN32
/* Windows doesn't know "%z" */
FormatDebug(curl_domain, "icy-metaint=%zu", icy_metaint);
#endif
@@ -372,6 +382,11 @@ CurlInputStream::InitEasy()
request_headers.Clear();
request_headers.Append("Icy-Metadata: 1");
}
void
CurlInputStream::StartRequest()
{
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
request->Start();
@@ -398,7 +413,8 @@ CurlInputStream::SeekInternal(offset_type new_offset)
/* send the "Range" header */
if (offset > 0) {
#ifdef WIN32
char range[32];
#ifdef _WIN32
// TODO: what can we use on Windows to format 64 bit?
sprintf(range, "%lu-", (long)offset);
#else
@@ -406,6 +422,8 @@ CurlInputStream::SeekInternal(offset_type new_offset)
#endif
request->SetOption(CURLOPT_RANGE, range);
}
StartRequest();
}
void
@@ -428,6 +446,7 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond)
try {
BlockingCall(io_thread_get(), [c](){
c->InitEasy();
c->StartRequest();
});
} catch (...) {
delete c;

@@ -104,7 +104,13 @@ input_ffmpeg_open(const char *uri,
size_t
FfmpegInputStream::Read(void *ptr, size_t read_size)
{
auto result = avio_read(h, (unsigned char *)ptr, read_size);
int result;
{
const ScopeUnlock unlock(mutex);
result = avio_read(h, (unsigned char *)ptr, read_size);
}
if (result <= 0) {
if (result < 0)
throw MakeFfmpegError(result, "avio_read() failed");
@@ -126,7 +132,12 @@ FfmpegInputStream::IsEOF() noexcept
void
FfmpegInputStream::Seek(offset_type new_offset)
{
auto result = avio_seek(h, new_offset, SEEK_SET);
int64_t result;
{
const ScopeUnlock unlock(mutex);
result = avio_seek(h, new_offset, SEEK_SET);
}
if (result < 0)
throw MakeFfmpegError(result, "avio_seek() failed");

@@ -87,14 +87,24 @@ input_file_open(gcc_unused const char *filename,
void
FileInputStream::Seek(offset_type new_offset)
{
reader.Seek((off_t)new_offset);
{
const ScopeUnlock unlock(mutex);
reader.Seek((off_t)new_offset);
}
offset = new_offset;
}
size_t
FileInputStream::Read(void *ptr, size_t read_size)
{
size_t nbytes = reader.Read(ptr, read_size);
size_t nbytes;
{
const ScopeUnlock unlock(mutex);
nbytes = reader.Read(ptr, read_size);
}
offset += nbytes;
return nbytes;
}

@@ -125,9 +125,14 @@ input_smbclient_open(const char *uri,
size_t
SmbclientInputStream::Read(void *ptr, size_t read_size)
{
smbclient_mutex.lock();
ssize_t nbytes = smbc_read(fd, ptr, read_size);
smbclient_mutex.unlock();
ssize_t nbytes;
{
const ScopeUnlock unlock(mutex);
const std::lock_guard<Mutex> lock(smbclient_mutex);
nbytes = smbc_read(fd, ptr, read_size);
}
if (nbytes < 0)
throw MakeErrno("smbc_read() failed");
@@ -138,9 +143,14 @@ SmbclientInputStream::Read(void *ptr, size_t read_size)
void
SmbclientInputStream::Seek(offset_type new_offset)
{
smbclient_mutex.lock();
off_t result = smbc_lseek(fd, new_offset, SEEK_SET);
smbclient_mutex.unlock();
off_t result;
{
const ScopeUnlock unlock(mutex);
const std::lock_guard<Mutex> lock(smbclient_mutex);
result = smbc_lseek(fd, new_offset, SEEK_SET);
}
if (result < 0)
throw MakeErrno("smbc_lseek() failed");

@@ -36,7 +36,7 @@
#include <ctype.h>
#endif
#ifdef WIN32
#ifdef _WIN32
#include "Win32.hxx"
#include <windows.h>
#endif
@@ -73,7 +73,7 @@ try {
folded.SetSize(folded_length);
return UCharToUTF8({folded.begin(), folded.size()});
#elif defined(WIN32)
#elif defined(_WIN32)
const auto u = MultiByteToWideChar(CP_UTF8, src);
const int size = LCMapStringEx(LOCALE_NAME_INVARIANT,

@@ -32,7 +32,7 @@
#include <ctype.h>
#endif
#ifdef WIN32
#ifdef _WIN32
#include "Win32.hxx"
#include "util/AllocatedString.hxx"
#include <windows.h>
@@ -103,7 +103,7 @@ IcuCollate(const char *a, const char *b) noexcept
}
#endif
#elif defined(WIN32)
#elif defined(_WIN32)
AllocatedString<wchar_t> wa = nullptr, wb = nullptr;
try {

@@ -22,7 +22,7 @@
#include "Compiler.h"
#include <upnp/upnptools.h>
#include <upnptools.h>
static inline constexpr unsigned
CountNameValuePairs()

@@ -20,7 +20,7 @@
#ifndef MPD_UPNP_CALLBACK_HXX
#define MPD_UPNP_CALLBACK_HXX
#include <upnp/upnp.h>
#include <upnp.h>
/**
* A class that is supposed to be used for libupnp asynchronous
@@ -40,7 +40,7 @@ public:
return *(UpnpCallback *)cookie;
}
virtual int Invoke(Upnp_EventType et, void *evp) = 0;
virtual int Invoke(Upnp_EventType et, const void *evp) = 0;
};
#endif

@@ -24,7 +24,7 @@
#include "thread/Mutex.hxx"
#include "util/RuntimeError.hxx"
#include <upnp/upnptools.h>
#include <upnptools.h>
#include <assert.h>
@@ -33,7 +33,12 @@ static unsigned upnp_client_ref;
static UpnpClient_Handle upnp_client_handle;
static int
UpnpClientCallback(Upnp_EventType et, void *evp, void *cookie)
UpnpClientCallback(Upnp_EventType et,
#if UPNP_VERSION >= 10800
const
#endif
void *evp,
void *cookie)
{
if (cookie == nullptr)
/* this is the cookie passed to UpnpRegisterClient();

@@ -22,7 +22,7 @@
#include "check.h"
#include <upnp/upnp.h>
#include <upnp.h>
void
UpnpClientGlobalInit(UpnpClient_Handle &handle);

72
src/lib/upnp/Compat.hxx Normal file

@@ -0,0 +1,72 @@
/*
* Copyright 2003-2017 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_UPNP_COMPAT_HXX
#define MPD_UPNP_COMPAT_HXX
#include <upnp.h>
#if UPNP_VERSION < 10800
/* emulate the libupnp 1.8 API with older versions */
using UpnpDiscovery = Upnp_Discovery;
#endif
#if UPNP_VERSION < 10624
#include "Compiler.h"
gcc_pure
static inline int
UpnpDiscovery_get_Expires(const UpnpDiscovery *disco) noexcept
{
return disco->Expires;
}
gcc_pure
static inline const char *
UpnpDiscovery_get_DeviceID_cstr(const UpnpDiscovery *disco) noexcept
{
return disco->DeviceId;
}
gcc_pure
static inline const char *
UpnpDiscovery_get_DeviceType_cstr(const UpnpDiscovery *disco) noexcept
{
return disco->DeviceType;
}
gcc_pure
static inline const char *
UpnpDiscovery_get_ServiceType_cstr(const UpnpDiscovery *disco) noexcept
{
return disco->ServiceType;
}
gcc_pure
static inline const char *
UpnpDiscovery_get_Location_cstr(const UpnpDiscovery *disco) noexcept
{
return disco->Location;
}
#endif
#endif

@@ -22,7 +22,7 @@
#include "Compiler.h"
#include <upnp/upnp.h>
#include <upnp.h>
#include <string>
#include <list>

@@ -24,7 +24,7 @@
#include "util/ScopeExit.hxx"
#include "util/RuntimeError.hxx"
#include <upnp/upnptools.h>
#include <upnptools.h>
#include <stdlib.h>
#include <string.h>
@@ -153,10 +153,10 @@ UPnPDeviceDirectory::Explore(void *ctx)
}
inline int
UPnPDeviceDirectory::OnAlive(Upnp_Discovery *disco)
UPnPDeviceDirectory::OnAlive(const UpnpDiscovery *disco)
{
if (isMSDevice(disco->DeviceType) ||
isCDService(disco->ServiceType)) {
if (isMSDevice(UpnpDiscovery_get_DeviceType_cstr(disco)) ||
isCDService(UpnpDiscovery_get_ServiceType_cstr(disco))) {
DiscoveredTask *tp = new DiscoveredTask(disco);
if (queue.put(tp))
return UPNP_E_FINISH;
@@ -166,12 +166,12 @@ UPnPDeviceDirectory::OnAlive(Upnp_Discovery *disco)
}
inline int
UPnPDeviceDirectory::OnByeBye(Upnp_Discovery *disco)
UPnPDeviceDirectory::OnByeBye(const UpnpDiscovery *disco)
{
if (isMSDevice(disco->DeviceType) ||
isCDService(disco->ServiceType)) {
if (isMSDevice(UpnpDiscovery_get_DeviceType_cstr(disco)) ||
isCDService(UpnpDiscovery_get_ServiceType_cstr(disco))) {
// Device signals it is going off.
LockRemove(disco->DeviceId);
LockRemove(UpnpDiscovery_get_DeviceID_cstr(disco));
}
return UPNP_E_SUCCESS;
@@ -182,19 +182,19 @@ UPnPDeviceDirectory::OnByeBye(Upnp_Discovery *disco)
// Example: ContentDirectories appearing and disappearing from the network
// We queue a task for our worker thread(s)
int
UPnPDeviceDirectory::Invoke(Upnp_EventType et, void *evp)
UPnPDeviceDirectory::Invoke(Upnp_EventType et, const void *evp)
{
switch (et) {
case UPNP_DISCOVERY_SEARCH_RESULT:
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
{
Upnp_Discovery *disco = (Upnp_Discovery *)evp;
auto *disco = (const UpnpDiscovery *)evp;
return OnAlive(disco);
}
case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
{
Upnp_Discovery *disco = (Upnp_Discovery *)evp;
auto *disco = (const UpnpDiscovery *)evp;
return OnByeBye(disco);
}

@@ -20,13 +20,14 @@
#ifndef _UPNPPDISC_H_X_INCLUDED_
#define _UPNPPDISC_H_X_INCLUDED_
#include "Compat.hxx"
#include "Callback.hxx"
#include "Device.hxx"
#include "WorkQueue.hxx"
#include "thread/Mutex.hxx"
#include "Compiler.h"
#include <upnp/upnp.h>
#include <upnp.h>
#include <list>
#include <vector>
@@ -34,6 +35,10 @@
#include <memory>
#include <chrono>
#if UPNP_VERSION < 10800
#define UpnpDiscovery Upnp_Discovery
#endif
class ContentDirectoryService;
class UPnPDiscoveryListener {
@@ -59,10 +64,10 @@ class UPnPDeviceDirectory final : UpnpCallback {
std::string device_id;
std::chrono::steady_clock::duration expires;
DiscoveredTask(const Upnp_Discovery *disco)
:url(disco->Location),
device_id(disco->DeviceId),
expires(std::chrono::seconds(disco->Expires)) {}
DiscoveredTask(const UpnpDiscovery *disco)
:url(UpnpDiscovery_get_Location_cstr(disco)),
device_id(UpnpDiscovery_get_DeviceID_cstr(disco)),
expires(std::chrono::seconds(UpnpDiscovery_get_Expires(disco))) {}
};
/**
@@ -153,11 +158,11 @@ private:
static void *Explore(void *);
void Explore();
int OnAlive(Upnp_Discovery *disco);
int OnByeBye(Upnp_Discovery *disco);
int OnAlive(const UpnpDiscovery *disco);
int OnByeBye(const UpnpDiscovery *disco);
/* virtual methods from class UpnpCallback */
virtual int Invoke(Upnp_EventType et, void *evp) override;
virtual int Invoke(Upnp_EventType et, const void *evp) override;
};

@@ -22,9 +22,9 @@
#include "thread/Mutex.hxx"
#include "util/RuntimeError.hxx"
#include <upnp/upnp.h>
#include <upnp/upnptools.h>
#include <upnp/ixml.h>
#include <upnp.h>
#include <upnptools.h>
#include <ixml.h>
#include <assert.h>

@@ -20,7 +20,7 @@
#ifndef MPD_UPNP_UNIQUE_XML_HXX
#define MPD_UPNP_UNIQUE_XML_HXX
#include <upnp/ixml.h>
#include <ixml.h>
#include <memory>

@@ -17,7 +17,7 @@
#ifndef _IXMLWRAP_H_INCLUDED_
#define _IXMLWRAP_H_INCLUDED_
#include <upnp/ixml.h>
#include <ixml.h>
#include <string>

@@ -292,7 +292,9 @@ AlsaMixer::SetVolume(unsigned volume)
{
assert(handle != nullptr);
int err = set_normalized_playback_volume(elem, 0.01*volume, 1);
double cur = get_normalized_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT);
int delta = volume - lrint(100.*cur);
int err = set_normalized_playback_volume(elem, cur + 0.01*delta, delta);
if (err < 0)
throw FormatRuntimeError("failed to set ALSA volume: %s",
snd_strerror(err));

@@ -23,7 +23,7 @@
#include <string>
#ifdef WIN32
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <sys/types.h>

@@ -34,7 +34,7 @@
#include <cstddef>
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
@@ -45,7 +45,7 @@
*/
class SocketAddress {
public:
#ifdef WIN32
#ifdef _WIN32
typedef int size_type;
#else
typedef socklen_t size_type;

@@ -23,7 +23,7 @@
#include <string.h>
#ifdef WIN32
#ifdef _WIN32
SocketErrorMessage::SocketErrorMessage(socket_error_t code) noexcept
{

@@ -23,7 +23,7 @@
#include "Compiler.h"
#include "system/Error.hxx"
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
typedef DWORD socket_error_t;
#else
@@ -35,7 +35,7 @@ gcc_pure
static inline socket_error_t
GetSocketError() noexcept
{
#ifdef WIN32
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
@@ -46,7 +46,7 @@ gcc_const
static inline bool
IsSocketErrorAgain(socket_error_t code) noexcept
{
#ifdef WIN32
#ifdef _WIN32
return code == WSAEINPROGRESS;
#else
return code == EAGAIN;
@@ -57,7 +57,7 @@ gcc_const
static inline bool
IsSocketErrorInterruped(socket_error_t code) noexcept
{
#ifdef WIN32
#ifdef _WIN32
return code == WSAEINTR;
#else
return code == EINTR;
@@ -68,7 +68,7 @@ gcc_const
static inline bool
IsSocketErrorClosed(socket_error_t code) noexcept
{
#ifdef WIN32
#ifdef _WIN32
return code == WSAECONNRESET;
#else
return code == EPIPE || code == ECONNRESET;
@@ -81,7 +81,7 @@ IsSocketErrorClosed(socket_error_t code) noexcept
* and this class hosts the buffer.
*/
class SocketErrorMessage {
#ifdef WIN32
#ifdef _WIN32
char msg[256];
#else
const char *const msg;
@@ -99,7 +99,7 @@ gcc_const
static inline std::system_error
MakeSocketError(socket_error_t code, const char *msg) noexcept
{
#ifdef WIN32
#ifdef _WIN32
return MakeLastError(code, msg);
#else
return MakeErrno(code, msg);

@@ -34,7 +34,7 @@
#include <algorithm>
#ifdef WIN32
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <netdb.h>

@@ -271,16 +271,15 @@ try {
inline bool
AudioOutput::PlayChunk()
{
if (tags) {
const auto *tag = source.ReadTag();
if (tag != nullptr) {
const ScopeUnlock unlock(mutex);
try {
ao_plugin_send_tag(this, *tag);
} catch (const std::runtime_error &e) {
FormatError(e, "Failed to send tag to \"%s\" [%s]",
name, plugin.name);
}
// ensure pending tags are flushed in all cases
const auto *tag = source.ReadTag();
if (tags && tag != nullptr) {
const ScopeUnlock unlock(mutex);
try {
ao_plugin_send_tag(this, *tag);
} catch (const std::runtime_error &e) {
FormatError(e, "Failed to send tag to \"%s\" [%s]",
name, plugin.name);
}
}

@@ -142,7 +142,8 @@ AudioOutputSource::GetChunkData(const MusicChunk &chunk,
replay_gain_filter_set_mode(*replay_gain_filter,
replay_gain_mode);
if (chunk.replay_gain_serial != *replay_gain_serial_p) {
if (chunk.replay_gain_serial != *replay_gain_serial_p &&
chunk.replay_gain_serial != MusicChunk::IGNORE_REPLAY_GAIN) {
replay_gain_filter_set_info(*replay_gain_filter,
chunk.replay_gain_serial != 0
? &chunk.replay_gain_info

@@ -36,9 +36,10 @@
#include <memory>
static constexpr unsigned MPD_OSX_BUFFER_TIME_MS = 100;
struct OSXOutput {
AudioOutput base;
/* configuration settings */
OSType component_subtype;
/* only applicable with kAudioUnitSubType_HALOutput */
@@ -693,7 +694,9 @@ osx_output_open(AudioOutput *ao, AudioFormat &audio_format)
errormsg);
}
od->ring_buffer = new boost::lockfree::spsc_queue<uint8_t>(buffer_frame_size);
size_t ring_buffer_size = std::max<size_t>(buffer_frame_size,
MPD_OSX_BUFFER_TIME_MS * audio_format.GetFrameSize() * audio_format.sample_rate / 1000);
od->ring_buffer = new boost::lockfree::spsc_queue<uint8_t>(ring_buffer_size);
status = AudioOutputUnitStart(od->au);
if (status != 0) {
@@ -717,7 +720,7 @@ osx_output_delay(AudioOutput *ao) noexcept
OSXOutput *od = (OSXOutput *)ao;
return od->ring_buffer->write_available()
? std::chrono::steady_clock::duration::zero()
: std::chrono::milliseconds(25);
: std::chrono::milliseconds(MPD_OSX_BUFFER_TIME_MS / 4);
}
int

@@ -468,6 +468,7 @@ HttpdOutput::SendTag(const Tag &tag)
try {
encoder->SendTag(tag);
encoder->Flush();
} catch (const std::runtime_error &) {
/* ignore */
}

@@ -24,7 +24,7 @@
#include <stdint.h>
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
/* on WIN32, "FLOAT" is already defined, and this triggers -Wshadow */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
@@ -57,7 +57,7 @@ enum class SampleFormat : uint8_t {
DSD,
};
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop
#endif

@@ -32,6 +32,7 @@
#include "output/MultipleOutputs.hxx"
#include "tag/Tag.hxx"
#include "Idle.hxx"
#include "system/PeriodClock.hxx"
#include "util/Domain.hxx"
#include "thread/Name.hxx"
#include "Log.hxx"
@@ -146,6 +147,8 @@ class Player {
*/
SongTime elapsed_time;
PeriodClock throttle_silence_log;
public:
Player(PlayerControl &_pc, DecoderControl &_dc,
MusicBuffer &_buffer)
@@ -555,8 +558,10 @@ Player::SendSilence()
partial frames */
unsigned num_frames = sizeof(chunk->data) / frame_size;
chunk->bit_rate = 0;
chunk->time = SignedSongTime::Negative(); /* undefined time stamp */
chunk->length = num_frames * frame_size;
chunk->replay_gain_serial = MusicChunk::IGNORE_REPLAY_GAIN;
PcmSilence({chunk->data, chunk->length}, play_audio_format.format);
try {
@@ -934,6 +939,8 @@ Player::SongBorder()
{
FormatDefault(player_domain, "played \"%s\"", song->GetURI());
throttle_silence_log.Reset();
ReplacePipe(dc.pipe);
pc.outputs.SongBorder();
@@ -1095,6 +1102,10 @@ Player::Run()
/* the decoder is too busy and hasn't provided
new PCM data in time: send silence (if the
output pipe is empty) */
if (throttle_silence_log.CheckUpdate(std::chrono::seconds(5)))
FormatWarning(player_domain, "Decoder is too slow; playing silence to avoid xrun");
if (!SendSilence())
break;
}

@@ -195,7 +195,7 @@ playlist_list_open_stream_mime2(InputStreamPtr &&is, const char *mime)
/* rewind the stream, so each plugin gets a
fresh start */
try {
is->Rewind();
is->LockRewind();
} catch (const std::runtime_error &) {
}
@@ -239,7 +239,7 @@ playlist_list_open_stream_suffix(InputStreamPtr &&is, const char *suffix)
/* rewind the stream, so each plugin gets a
fresh start */
try {
is->Rewind();
is->LockRewind();
} catch (const std::runtime_error &) {
}

@@ -75,8 +75,7 @@ playlist::MoveOrderToCurrent(unsigned old_order)
} else {
/* not playing anything: move the specified song to
the front */
queue.SwapOrders(old_order, 0);
return 0;
return queue.MoveOrderBefore(old_order, 0);
}
}

@@ -112,7 +112,7 @@ playlist::AppendSong(PlayerControl &pc, DetachedSong &&song)
else
start = current + 1;
if (start < queue.GetLength())
queue.ShuffleOrderLast(start, queue.GetLength());
queue.ShuffleOrderLastWithPriority(start, queue.GetLength());
}
UpdateQueuedSong(pc, queued_song);

@@ -364,8 +364,20 @@ Queue::ShuffleOrderFirst(unsigned start, unsigned end)
}
void
Queue::ShuffleOrderLast(unsigned start, unsigned end)
Queue::ShuffleOrderLastWithPriority(unsigned start, unsigned end)
{
assert(end <= length);
assert(start < end);
/* skip all items at the start which have a higher priority,
because the last item shall only be shuffled within its
priority group */
const auto last_priority = items[OrderToPosition(end - 1)].priority;
while (items[OrderToPosition(start)].priority != last_priority) {
++start;
assert(start < end);
}
rand.AutoCreate();
std::uniform_int_distribution<unsigned> distribution(start, end - 1);

@@ -356,11 +356,12 @@ struct Queue {
void ShuffleOrderFirst(unsigned start, unsigned end);
/**
* Shuffles the virtual order of the last song in the specified
* (order) range. This is used in random mode after a song has been
* appended by queue_append().
* Shuffles the virtual order of the last song in the
* specified (order) range; only songs which match this song's
* priority are considered. This is used in random mode after
* a song has been appended by Append().
*/
void ShuffleOrderLast(unsigned start, unsigned end);
void ShuffleOrderLastWithPriority(unsigned start, unsigned end);
/**
* Shuffles a (position) range in the queue. The songs are physically

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