Compare commits
89 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
323231d1dd | ||
![]() |
714011c81e | ||
![]() |
952ff4207b | ||
![]() |
150b16ec2c | ||
![]() |
c98bc4a243 | ||
![]() |
014f8cd693 | ||
![]() |
aea37e46e3 | ||
![]() |
31ab78ae8e | ||
![]() |
f82e1453e4 | ||
![]() |
a2b77c8813 | ||
![]() |
18add29472 | ||
![]() |
b111a8fe8d | ||
![]() |
3b23cf0258 | ||
![]() |
28e864e096 | ||
![]() |
1de19b921a | ||
![]() |
ff162b5a03 | ||
![]() |
d8e4705dd4 | ||
![]() |
338e1f5926 | ||
![]() |
a7fdfa08e1 | ||
![]() |
9703a401c5 | ||
![]() |
753a2aa462 | ||
![]() |
10990a0684 | ||
![]() |
91254e9211 | ||
![]() |
0f79287b04 | ||
![]() |
f2fac77d8c | ||
![]() |
81b7373637 | ||
![]() |
fa67c2548a | ||
![]() |
ea80587ddb | ||
![]() |
828f5f8384 | ||
![]() |
1295a1272a | ||
![]() |
66646d9276 | ||
![]() |
d0497dba92 | ||
![]() |
42914e8227 | ||
![]() |
59b49b7881 | ||
![]() |
5620f16330 | ||
![]() |
be024d4ad7 | ||
![]() |
75c740fe2b | ||
![]() |
6c8d86bb90 | ||
![]() |
b253a6b71e | ||
![]() |
ca7b4df812 | ||
![]() |
bc8dd57236 | ||
![]() |
f4f461b8bb | ||
![]() |
cbb9b6957f | ||
![]() |
f6b56c9317 | ||
![]() |
3717fb6c8d | ||
![]() |
f6abbc01bd | ||
![]() |
57a71c157d | ||
![]() |
cc76aeb7bb | ||
![]() |
811cabf8a9 | ||
![]() |
bf8d2f93d2 | ||
![]() |
07d8259ad6 | ||
![]() |
a00d412008 | ||
![]() |
5fb39658f1 | ||
![]() |
b0703b92c3 | ||
![]() |
dd9fd3d8a7 | ||
![]() |
cf0c59864f | ||
![]() |
4c0404c70d | ||
![]() |
573a413ee1 | ||
![]() |
f633e6ca49 | ||
![]() |
07b06d76be | ||
![]() |
856fe2da15 | ||
![]() |
f82aae65cd | ||
![]() |
3fbd11a104 | ||
![]() |
58a99f1907 | ||
![]() |
cf86dfd317 | ||
![]() |
a057b4f6d8 | ||
![]() |
62b03cfddf | ||
![]() |
18b827b979 | ||
![]() |
0a379fc514 | ||
![]() |
445c11b8d9 | ||
![]() |
8d290ad509 | ||
![]() |
b90c48b50f | ||
![]() |
d19e7db09e | ||
![]() |
9939904b02 | ||
![]() |
ca23b15f5c | ||
![]() |
ffa676f577 | ||
![]() |
6d023c4df3 | ||
![]() |
b31bd37a30 | ||
![]() |
78faee8c7c | ||
![]() |
40e2a703d0 | ||
![]() |
b01edcb9bc | ||
![]() |
f7fffc9be8 | ||
![]() |
50e8634097 | ||
![]() |
e3994e517e | ||
![]() |
2bb7785189 | ||
![]() |
90c8408111 | ||
![]() |
64786ec12a | ||
![]() |
b3c82f8886 | ||
![]() |
063259dc52 |
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
dist: trusty
|
||||||
|
language: cpp
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libcppunit-dev
|
||||||
|
- libboost-dev
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- MAKEFLAGS="-j2"
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
# C++14
|
||||||
|
- test "$TRAVIS_OS_NAME" != "linux" || sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||||
|
- test "$TRAVIS_OS_NAME" != "linux" || sudo apt-get update -qq
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || brew update
|
||||||
|
|
||||||
|
install:
|
||||||
|
# C++14
|
||||||
|
- test "$TRAVIS_OS_NAME" != "linux" || sudo apt-get install -qq g++-5
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || brew install cppunit
|
||||||
|
|
||||||
|
script:
|
||||||
|
- OPTIONS="--enable-test"
|
||||||
|
- test "$TRAVIS_OS_NAME" != "linux" || export CC=gcc-5 CXX=g++-5
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || OPTIONS="$OPTIONS --enable-osx"
|
||||||
|
- ./autogen.sh
|
||||||
|
- ./configure --disable-silent-rules --disable-dependency-tracking $OPTIONS
|
||||||
|
- make
|
||||||
|
- make check
|
1
AUTHORS
1
AUTHORS
@@ -30,3 +30,4 @@ The following people have contributed code to MPD:
|
|||||||
Jurgen Kramer <gtmkramer@xs4all.nl>
|
Jurgen Kramer <gtmkramer@xs4all.nl>
|
||||||
Jean-Francois Dockes <jf@dockes.org>
|
Jean-Francois Dockes <jf@dockes.org>
|
||||||
Yue Wang <yuleopen@gmail.com>
|
Yue Wang <yuleopen@gmail.com>
|
||||||
|
Matthew Leon Grinshpun <ml@matthewleon.com>
|
||||||
|
206
INSTALL
206
INSTALL
@@ -1,206 +0,0 @@
|
|||||||
Music Player Daemon (MPD) - INSTALL
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
------------
|
|
||||||
|
|
||||||
This document is a very small amount of documentation about what is needed to
|
|
||||||
install MPD. If more information is desired, read the user manual:
|
|
||||||
|
|
||||||
http://www.musicpd.org/doc/user/
|
|
||||||
|
|
||||||
Dependencies
|
|
||||||
------------
|
|
||||||
|
|
||||||
gcc 4.7 or later - http://gcc.gnu.org/
|
|
||||||
clang 3.2 or later - http://clang.llvm.org/
|
|
||||||
Any other C++11 compliant compiler should also work.
|
|
||||||
|
|
||||||
Boost 1.46 - http://www.boost.org/
|
|
||||||
|
|
||||||
|
|
||||||
Optional Output Dependencies
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
You will need at least one of these to compile MPD.
|
|
||||||
|
|
||||||
Most of these are available as packages on major distributions. Be sure to
|
|
||||||
install both the library package as well as the development package.
|
|
||||||
|
|
||||||
AO - http://www.xiph.org/ao/
|
|
||||||
A portable library that abstracts many audio output types as one API. Should
|
|
||||||
be used only if there is no native plugin available or if the native plugin
|
|
||||||
doesn't work. You will need libao.
|
|
||||||
|
|
||||||
ALSA - http://www.alsa-project.org/
|
|
||||||
The Advanced Linux Sound Architecture. Recommended audio output if you use
|
|
||||||
Linux. You will need libasound.
|
|
||||||
|
|
||||||
FIFO
|
|
||||||
This is a mostly undocumented, developer plugin to transmit raw data.
|
|
||||||
|
|
||||||
OSS - http://www.opensound.com
|
|
||||||
Open Sound System.
|
|
||||||
|
|
||||||
PulseAudio - http://www.pulseaudio.org/
|
|
||||||
An advanced sound daemon. You will need libpulse.
|
|
||||||
|
|
||||||
JACK - http://www.jackaudio.org/
|
|
||||||
A low-latency sound daemon.
|
|
||||||
|
|
||||||
libshout - http://www.icecast.org/
|
|
||||||
For streaming to an Icecast or Shoutcast server.
|
|
||||||
You also need an encoder: either libvorbisenc (ogg), or liblame (mp3).
|
|
||||||
|
|
||||||
OpenAL - http://kcat.strangesoft.net/openal.html
|
|
||||||
Open Audio Library
|
|
||||||
|
|
||||||
|
|
||||||
Optional Input Dependencies
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
You will need at least one of these to compile MPD.
|
|
||||||
|
|
||||||
Most of these are available as packages on major distributions. Be sure to
|
|
||||||
install both the library package as well as the development package.
|
|
||||||
|
|
||||||
MAD - http://www.underbit.com/products/mad/
|
|
||||||
For MP3 support. You will need libmad, and optionally libid3tag if you want
|
|
||||||
ID3 tag support.
|
|
||||||
|
|
||||||
libmpg123 - http://www.mpg123.de/
|
|
||||||
Alternative for MP3 support.
|
|
||||||
|
|
||||||
Ogg Vorbis - http://www.xiph.org/ogg/vorbis/
|
|
||||||
For Ogg Vorbis support. You will need libogg and libvorbis.
|
|
||||||
|
|
||||||
libopus - http://www.opus-codec.org/
|
|
||||||
Opus codec support
|
|
||||||
|
|
||||||
FLAC - http://flac.sourceforge.net/
|
|
||||||
For FLAC support. You will need version 1.2 or higher of libFLAC.
|
|
||||||
|
|
||||||
Audio File - http://www.68k.org/~michael/audiofile/
|
|
||||||
For WAVE, AIFF, and AU support. You will need libaudiofile.
|
|
||||||
|
|
||||||
FAAD2 - http://www.audiocoding.com/
|
|
||||||
For MP4/AAC support.
|
|
||||||
|
|
||||||
libmpcdec - http://www.musepack.net/
|
|
||||||
For Musepack support.
|
|
||||||
|
|
||||||
MikMod - http://mikmod.raphnet.net/
|
|
||||||
For MOD support. You will need libmikmod.
|
|
||||||
|
|
||||||
libavcodec, libavformat (ffmpeg or libav) - http://ffmpeg.mplayerhq.hu/ http://libav.org/
|
|
||||||
Multi-codec library.
|
|
||||||
|
|
||||||
libsidplay2 - http://sidplay2.sourceforge.net/
|
|
||||||
For C64 SID support.
|
|
||||||
|
|
||||||
libfluidsynth - http://fluidsynth.resonance.org/
|
|
||||||
For MIDI support.
|
|
||||||
|
|
||||||
libwildmidi 0.2.3 - http://wildmidi.sourceforge.net/
|
|
||||||
For MIDI support.
|
|
||||||
|
|
||||||
libsndfile - http://www.mega-nerd.com/libsndfile/
|
|
||||||
WAVE, AIFF, and many others.
|
|
||||||
|
|
||||||
libwavpack - http://www.wavpack.com/
|
|
||||||
For WavPack playback.
|
|
||||||
|
|
||||||
libadplug - http://adplug.sourceforge.net/
|
|
||||||
For AdLib playback.
|
|
||||||
|
|
||||||
|
|
||||||
Optional Miscellaneous Dependencies
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
Avahi - http://www.avahi.org/
|
|
||||||
For Zeroconf support.
|
|
||||||
|
|
||||||
libsamplerate - http://www.mega-nerd.com/SRC/
|
|
||||||
For advanced samplerate conversions.
|
|
||||||
|
|
||||||
libcurl - http://curl.haxx.se/
|
|
||||||
For playing HTTP streams.
|
|
||||||
|
|
||||||
libmms - https://launchpad.net/libmms
|
|
||||||
For playing MMS streams.
|
|
||||||
|
|
||||||
SQLite - http://www.sqlite.org/
|
|
||||||
For the sticker database.
|
|
||||||
|
|
||||||
libcdio - http://www.gnu.org/software/libcdio/
|
|
||||||
For playing audio CDs.
|
|
||||||
|
|
||||||
libsystemd-daemon - http://freedesktop.org/wiki/Software/systemd/
|
|
||||||
For systemd activation.
|
|
||||||
|
|
||||||
|
|
||||||
pkg-config
|
|
||||||
----------
|
|
||||||
|
|
||||||
MPD uses pkg-config to locate most external libraries. If you do not
|
|
||||||
have pkg-config, or if your version of the library does not ship the
|
|
||||||
".pc" file, you have to provide the library's build options in
|
|
||||||
environment variables. These variables are documented in "./configure
|
|
||||||
--help". Example:
|
|
||||||
|
|
||||||
FLAC_CFLAGS=-I/usr/include/FLAC FLAC_LIBS=-lFLAC ./configure
|
|
||||||
|
|
||||||
|
|
||||||
Download
|
|
||||||
--------
|
|
||||||
|
|
||||||
Get the latest release from of MPD from <http://www.musicpd.org/>.
|
|
||||||
|
|
||||||
Compile
|
|
||||||
-------
|
|
||||||
|
|
||||||
1) unpack the archive
|
|
||||||
|
|
||||||
$ tar xf mpd-x.x.x.tar.xz
|
|
||||||
|
|
||||||
2) change to directory created
|
|
||||||
|
|
||||||
$ cd mpd-x.x.x
|
|
||||||
|
|
||||||
3) Run configure script (this will determine what dependencies you have)
|
|
||||||
|
|
||||||
$ ./configure
|
|
||||||
|
|
||||||
4) Compile
|
|
||||||
|
|
||||||
$ make
|
|
||||||
|
|
||||||
Install (Optional)
|
|
||||||
-------
|
|
||||||
|
|
||||||
(as root)
|
|
||||||
$ make install
|
|
||||||
|
|
||||||
Run
|
|
||||||
---
|
|
||||||
|
|
||||||
1) run mpd:
|
|
||||||
|
|
||||||
$ mpd <config file>
|
|
||||||
|
|
||||||
First default is $XDG_CONFIG_HOME/mpd/mpd.conf then ~/.mpdconf then
|
|
||||||
~/.mpd/mpd.conf then /etc/mpd.conf. If neither of these exist a mpd
|
|
||||||
configuration file must be specified at runtime.
|
|
||||||
|
|
||||||
A sample config file is included with the source of MPD, mpdconf.example.
|
|
||||||
|
|
||||||
The first time MPD is run it will attempt to discover all music in your
|
|
||||||
music root, recursively. This can be affected by the symbolic link
|
|
||||||
options specified in the example mpd.conf.
|
|
||||||
|
|
||||||
Using MPD
|
|
||||||
---------
|
|
||||||
|
|
||||||
You can download many different interfaces for MPD at
|
|
||||||
|
|
||||||
http://www.musicpd.org/clients/
|
|
@@ -243,6 +243,7 @@ CURL_SOURCES = \
|
|||||||
src/lib/curl/Slist.hxx
|
src/lib/curl/Slist.hxx
|
||||||
|
|
||||||
UPNP_SOURCES = \
|
UPNP_SOURCES = \
|
||||||
|
src/lib/upnp/Compat.hxx \
|
||||||
src/lib/upnp/Init.cxx src/lib/upnp/Init.hxx \
|
src/lib/upnp/Init.cxx src/lib/upnp/Init.hxx \
|
||||||
src/lib/upnp/ClientInit.cxx src/lib/upnp/ClientInit.hxx \
|
src/lib/upnp/ClientInit.cxx src/lib/upnp/ClientInit.hxx \
|
||||||
src/lib/upnp/Device.cxx src/lib/upnp/Device.hxx \
|
src/lib/upnp/Device.cxx src/lib/upnp/Device.hxx \
|
||||||
@@ -518,6 +519,8 @@ libevent_a_SOURCES = \
|
|||||||
# UTF-8 library
|
# UTF-8 library
|
||||||
|
|
||||||
libicu_a_SOURCES = \
|
libicu_a_SOURCES = \
|
||||||
|
src/lib/icu/CaseFold.cxx src/lib/icu/CaseFold.hxx \
|
||||||
|
src/lib/icu/Compare.cxx src/lib/icu/Compare.hxx \
|
||||||
src/lib/icu/Collate.cxx src/lib/icu/Collate.hxx \
|
src/lib/icu/Collate.cxx src/lib/icu/Collate.hxx \
|
||||||
src/lib/icu/Converter.cxx src/lib/icu/Converter.hxx
|
src/lib/icu/Converter.cxx src/lib/icu/Converter.hxx
|
||||||
|
|
||||||
@@ -923,6 +926,7 @@ libtag_a_SOURCES =\
|
|||||||
src/tag/ReplayGain.cxx src/tag/ReplayGain.hxx \
|
src/tag/ReplayGain.cxx src/tag/ReplayGain.hxx \
|
||||||
src/tag/MixRamp.cxx src/tag/MixRamp.hxx \
|
src/tag/MixRamp.cxx src/tag/MixRamp.hxx \
|
||||||
src/tag/Generic.cxx src/tag/Generic.hxx \
|
src/tag/Generic.cxx src/tag/Generic.hxx \
|
||||||
|
src/tag/Id3MusicBrainz.cxx src/tag/Id3MusicBrainz.hxx \
|
||||||
src/tag/ApeLoader.cxx src/tag/ApeLoader.hxx \
|
src/tag/ApeLoader.cxx src/tag/ApeLoader.hxx \
|
||||||
src/tag/ApeReplayGain.cxx src/tag/ApeReplayGain.hxx \
|
src/tag/ApeReplayGain.cxx src/tag/ApeReplayGain.hxx \
|
||||||
src/tag/ApeTag.cxx src/tag/ApeTag.hxx
|
src/tag/ApeTag.cxx src/tag/ApeTag.hxx
|
||||||
@@ -1489,6 +1493,8 @@ liboutput_plugins_a_SOURCES += \
|
|||||||
src/output/plugins/OSXOutputPlugin.cxx \
|
src/output/plugins/OSXOutputPlugin.cxx \
|
||||||
src/output/plugins/OSXOutputPlugin.hxx
|
src/output/plugins/OSXOutputPlugin.hxx
|
||||||
endif
|
endif
|
||||||
|
libmixer_plugins_a_SOURCES += \
|
||||||
|
src/mixer/plugins/OSXMixerPlugin.cxx
|
||||||
|
|
||||||
if ENABLE_PULSE
|
if ENABLE_PULSE
|
||||||
liboutput_plugins_a_SOURCES += \
|
liboutput_plugins_a_SOURCES += \
|
||||||
|
52
NEWS
52
NEWS
@@ -1,3 +1,55 @@
|
|||||||
|
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
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: more reliable song duration
|
||||||
|
- gme: fix track numbering
|
||||||
|
* improve random song order when switching songs manually
|
||||||
|
* fix case insensitive search without libicu
|
||||||
|
* fix Unicode file names in playlists on Windows
|
||||||
|
* fix endless loop when accessing malformed file names in ZIP files
|
||||||
|
|
||||||
|
ver 0.20.10 (2017/08/24)
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: support MusicBrainz ID3v2 tags
|
||||||
|
* tags
|
||||||
|
- aiff: fix FORM chunk size endianess (is big-endian)
|
||||||
|
* mixer
|
||||||
|
- osx: add a mixer for OSX.
|
||||||
|
* fix crash when resuming playback before decoder is ready
|
||||||
|
* fix crash on Windows
|
||||||
|
|
||||||
|
ver 0.20.9 (2017/06/04)
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: support *.adx
|
||||||
|
* fix byte order detection on FreeBSD/aarch64
|
||||||
|
* fix more random crashes when compiled with clang
|
||||||
|
|
||||||
|
ver 0.20.8 (2017/05/19)
|
||||||
|
* output
|
||||||
|
- osx: fix build failure due to missing "noexcept"
|
||||||
|
* playlist
|
||||||
|
- m3u: support MIME type `audio/mpegurl`
|
||||||
|
* fix build failure with GCC 4.x
|
||||||
|
|
||||||
ver 0.20.7 (2017/05/15)
|
ver 0.20.7 (2017/05/15)
|
||||||
* database
|
* database
|
||||||
- simple: fix false positive directory loop detection with NFS
|
- simple: fix false positive directory loop detection with NFS
|
||||||
|
@@ -7,7 +7,8 @@ server's audio device. The daemon stores info about all available music,
|
|||||||
and this info can be easily searched and retrieved. Player control, info
|
and this info can be easily searched and retrieved. Player control, info
|
||||||
retrieval, and playlist management can all be managed remotely.
|
retrieval, and playlist management can all be managed remotely.
|
||||||
|
|
||||||
For basic installation information see the INSTALL file.
|
For basic installation instructions
|
||||||
|
[read the manual](https://www.musicpd.org/doc/user/install.html).
|
||||||
|
|
||||||
# Users
|
# Users
|
||||||
|
|
||||||
|
@@ -154,5 +154,9 @@ configure = [
|
|||||||
|
|
||||||
] + configure_args
|
] + configure_args
|
||||||
|
|
||||||
|
from build.cmdline import concatenate_cmdline_variables
|
||||||
|
configure = concatenate_cmdline_variables(configure,
|
||||||
|
set(('CFLAGS', 'CXXFLAGS', 'CPPFLAGS', 'LDFLAGS', 'LIBS')))
|
||||||
|
|
||||||
subprocess.check_call(configure, env=toolchain.env)
|
subprocess.check_call(configure, env=toolchain.env)
|
||||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], env=toolchain.env)
|
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], env=toolchain.env)
|
||||||
|
10
configure.ac
10
configure.ac
@@ -1,10 +1,10 @@
|
|||||||
AC_PREREQ(2.60)
|
AC_PREREQ(2.60)
|
||||||
|
|
||||||
AC_INIT(mpd, 0.20.7, musicpd-dev-team@lists.sourceforge.net)
|
AC_INIT(mpd, 0.20.12, musicpd-dev-team@lists.sourceforge.net)
|
||||||
|
|
||||||
VERSION_MAJOR=0
|
VERSION_MAJOR=0
|
||||||
VERSION_MINOR=20
|
VERSION_MINOR=20
|
||||||
VERSION_REVISION=7
|
VERSION_REVISION=12
|
||||||
VERSION_EXTRA=0
|
VERSION_EXTRA=0
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([src/Main.cxx])
|
AC_CONFIG_SRCDIR([src/Main.cxx])
|
||||||
@@ -241,6 +241,7 @@ AC_CHECK_FUNCS(getpwnam_r getpwuid_r)
|
|||||||
AC_CHECK_FUNCS(initgroups)
|
AC_CHECK_FUNCS(initgroups)
|
||||||
AC_CHECK_FUNCS(fnmatch)
|
AC_CHECK_FUNCS(fnmatch)
|
||||||
AC_CHECK_FUNCS(strndup)
|
AC_CHECK_FUNCS(strndup)
|
||||||
|
AC_CHECK_FUNCS(strcasestr)
|
||||||
|
|
||||||
if test x$host_is_linux = xyes; then
|
if test x$host_is_linux = xyes; then
|
||||||
MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD)
|
MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD)
|
||||||
@@ -1384,6 +1385,11 @@ then
|
|||||||
AX_APPEND_COMPILE_FLAGS([-Wcast-qual])
|
AX_APPEND_COMPILE_FLAGS([-Wcast-qual])
|
||||||
AX_APPEND_COMPILE_FLAGS([-Wwrite-strings])
|
AX_APPEND_COMPILE_FLAGS([-Wwrite-strings])
|
||||||
AX_APPEND_COMPILE_FLAGS([-Wsign-compare])
|
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
|
AC_LANG_POP
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@@ -403,6 +403,15 @@
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Change events accumulate, even while the connection is
|
||||||
|
not in "idle" mode; no events gets lost while the client
|
||||||
|
is doing something else with the connection. If an
|
||||||
|
event had already occurred since the last call, the new
|
||||||
|
<command>idle</command> command will return immediately.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
While a client is waiting for <command>idle</command>
|
While a client is waiting for <command>idle</command>
|
||||||
results, the server disables timeouts, allowing a client
|
results, the server disables timeouts, allowing a client
|
||||||
@@ -436,7 +445,9 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<varname>volume</varname>:
|
<varname>volume</varname>:
|
||||||
<returnvalue>0-100</returnvalue>
|
<returnvalue>0-100</returnvalue> or
|
||||||
|
<returnvalue>-1</returnvalue> if the volume cannot
|
||||||
|
be determined
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
247
doc/user.xml
247
doc/user.xml
@@ -80,13 +80,40 @@
|
|||||||
cd mpd-version</programlisting>
|
cd mpd-version</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Make sure that all the required libraries and build tools are
|
In any case, you need:
|
||||||
installed. The <filename>INSTALL</filename> file has a list.
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a C++14 compiler (e.g. <ulink
|
||||||
|
url="http://gcc.gnu.org/">gcc 4.9</ulink> or <ulink
|
||||||
|
url="http://clang.llvm.org/">clang 3.9</ulink>)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<ulink url="http://www.boost.org/">Boost 1.46</ulink>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<ulink url="https://www.freedesktop.org/wiki/Software/pkg-config/">pkg-config</ulink>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Each plugin usually needs a codec library, which you also need
|
||||||
|
to install. Check the plugin reference for details about
|
||||||
|
required libraries.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For example, the following installs a fairly complete list of
|
For example, the following installs a fairly complete list of
|
||||||
build dependencies on Debian Wheezy:
|
build dependencies on Debian Jessie:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
@@ -98,19 +125,20 @@ apt-get install g++ \
|
|||||||
libmpcdec-dev libwavpack-dev libwildmidi-dev \
|
libmpcdec-dev libwavpack-dev libwildmidi-dev \
|
||||||
libsidplay2-dev libsidutils-dev libresid-builder-dev \
|
libsidplay2-dev libsidutils-dev libresid-builder-dev \
|
||||||
libavcodec-dev libavformat-dev \
|
libavcodec-dev libavformat-dev \
|
||||||
libmp3lame-dev \
|
libmp3lame-dev libtwolame-dev libshine-dev \
|
||||||
libsamplerate0-dev libsoxr-dev \
|
libsamplerate0-dev libsoxr-dev \
|
||||||
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
|
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
|
||||||
libzzip-dev \
|
libzzip-dev \
|
||||||
libcurl4-gnutls-dev libyajl-dev libexpat-dev \
|
libcurl4-gnutls-dev libyajl-dev libexpat-dev \
|
||||||
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
|
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
|
||||||
libpulse-dev libroar-dev libshout3-dev \
|
libpulse-dev libroar-dev libshout3-dev \
|
||||||
|
libsndio-dev \
|
||||||
libmpdclient-dev \
|
libmpdclient-dev \
|
||||||
libnfs-dev libsmbclient-dev \
|
libnfs-dev libsmbclient-dev \
|
||||||
libupnp-dev \
|
libupnp-dev \
|
||||||
libavahi-client-dev \
|
libavahi-client-dev \
|
||||||
libsqlite3-dev \
|
libsqlite3-dev \
|
||||||
libsystemd-daemon-dev libwrap0-dev \
|
libsystemd-dev libwrap0-dev \
|
||||||
libcppunit-dev xmlto \
|
libcppunit-dev xmlto \
|
||||||
libboost-dev \
|
libboost-dev \
|
||||||
libicu-dev
|
libicu-dev
|
||||||
@@ -1035,6 +1063,40 @@ systemctl start mpd.socket</programlisting>
|
|||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="stickers">
|
||||||
|
<title>The Sticker Database</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
"Stickers" are pieces of information attached to songs.
|
||||||
|
Some clients use them to store ratings and other volatile
|
||||||
|
data. This feature requires <ulink
|
||||||
|
url="http://www.sqlite.org/">SQLite</ulink>, compile-time
|
||||||
|
configure option <parameter>--enable-sqlite</parameter>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Setting</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>sticker_file</varname>
|
||||||
|
<parameter>PATH</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
The location of the sticker database.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>Resource Limitations</title>
|
<title>Resource Limitations</title>
|
||||||
|
|
||||||
@@ -1165,6 +1227,55 @@ systemctl start mpd.socket</programlisting>
|
|||||||
</tgroup>
|
</tgroup>
|
||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="zeroconf">
|
||||||
|
<title>Zeroconf</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If Zeroconf support (<ulink
|
||||||
|
url="http://avahi.org/">Avahi</ulink> or Apple's Bonjour)
|
||||||
|
was enabled at compile time with
|
||||||
|
<parameter>--with-zeroconf=...</parameter>, MPD can announce
|
||||||
|
its presence on the network. The following settings control
|
||||||
|
this feature:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Setting</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>zeroconf_enabled</varname>
|
||||||
|
<parameter>yes|no</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Enables or disables this feature. Default is
|
||||||
|
<parameter>yes</parameter>.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>zeroconf_name</varname>
|
||||||
|
<parameter>NAME</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
The service name to publish via Zeroconf. The
|
||||||
|
default is "<parameter>Music Player</parameter>".
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
@@ -2078,7 +2189,9 @@ run</programlisting>
|
|||||||
<title><varname>cdio_paranoia</varname></title>
|
<title><varname>cdio_paranoia</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Plays audio CDs. The URI has the form:
|
Plays audio CDs using <ulink
|
||||||
|
url="http://www.gnu.org/software/libcdio/"><filename>libcdio</filename></ulink>.
|
||||||
|
The URI has the form:
|
||||||
"<filename>cdda://[DEVICE][/TRACK]</filename>". The
|
"<filename>cdda://[DEVICE][/TRACK]</filename>". The
|
||||||
simplest form <filename>cdda://</filename> plays the whole
|
simplest form <filename>cdda://</filename> plays the whole
|
||||||
disc in the default drive.
|
disc in the default drive.
|
||||||
@@ -2114,7 +2227,8 @@ run</programlisting>
|
|||||||
<title><varname>curl</varname></title>
|
<title><varname>curl</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Opens remote files or streams over HTTP.
|
Opens remote files or streams over HTTP using <ulink
|
||||||
|
url="http://curl.haxx.se/"><filename>libcurl</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -2207,7 +2321,8 @@ run</programlisting>
|
|||||||
<title><varname>mms</varname></title>
|
<title><varname>mms</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Plays streams with the MMS protocol.
|
Plays streams with the MMS protocol using <ulink
|
||||||
|
url="https://launchpad.net/libmms"><filename>libmms</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2263,7 +2378,8 @@ run</programlisting>
|
|||||||
<title><varname>adplug</varname></title>
|
<title><varname>adplug</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes AdLib files.
|
Decodes AdLib files using <ulink
|
||||||
|
url="http://adplug.sourceforge.net/">libadplug</ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informaltable>
|
<informaltable>
|
||||||
@@ -2294,8 +2410,8 @@ run</programlisting>
|
|||||||
<title><varname>audiofile</varname></title>
|
<title><varname>audiofile</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes WAV and AIFF files using
|
Decodes WAV and AIFF files using <ulink
|
||||||
<filename>libaudiofile</filename>.
|
url="http://audiofile.68k.org/"><filename>libaudiofile</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2303,7 +2419,8 @@ run</programlisting>
|
|||||||
<title><varname>faad</varname></title>
|
<title><varname>faad</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes AAC files using <filename>libfaad</filename>.
|
Decodes AAC files using <ulink
|
||||||
|
url="http://www.audiocoding.com/"><filename>libfaad</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2311,8 +2428,8 @@ run</programlisting>
|
|||||||
<title><varname>ffmpeg</varname></title>
|
<title><varname>ffmpeg</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes various codecs using
|
Decodes various codecs using <ulink
|
||||||
<application>FFmpeg</application>.
|
url="https://ffmpeg.org/"><application>FFmpeg</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informaltable>
|
<informaltable>
|
||||||
@@ -2363,7 +2480,7 @@ run</programlisting>
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes FLAC files using
|
Decodes FLAC files using
|
||||||
<application>libFLAC</application>.
|
<ulink url="https://xiph.org/flac/"><application>libFLAC</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2483,7 +2600,8 @@ run</programlisting>
|
|||||||
<title><varname>mad</varname></title>
|
<title><varname>mad</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes MP3 files using <application>libmad</application>.
|
Decodes MP3 files using <ulink
|
||||||
|
url="http://www.underbit.com/products/mad/"><application>libmad</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2563,8 +2681,8 @@ run</programlisting>
|
|||||||
<title><varname>mpcdec</varname></title>
|
<title><varname>mpcdec</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes Musepack files using
|
Decodes Musepack files using <ulink
|
||||||
<application>libmpcdec</application>.
|
url="http://www.musepack.net/"><application>libmpcdec</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2572,7 +2690,17 @@ run</programlisting>
|
|||||||
<title><varname>mpg123</varname></title>
|
<title><varname>mpg123</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes MP3 files using <application>libmpg123</application>.
|
Decodes MP3 files using <ulink
|
||||||
|
url="http://www.mpg123.de/"><application>libmpg123</application></ulink>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="opus_decoder">
|
||||||
|
<title><varname>opus</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Decodes Opus files using <ulink
|
||||||
|
url="http://www.opus-codec.org/"><application>libopus</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2592,8 +2720,8 @@ run</programlisting>
|
|||||||
<title><varname>sidplay</varname></title>
|
<title><varname>sidplay</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
C64 SID decoder based on
|
C64 SID decoder based on <ulink
|
||||||
<application>libsidplay</application>.
|
url="http://sidplay2.sourceforge.net/"><application>libsidplay</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informaltable>
|
<informaltable>
|
||||||
@@ -2649,8 +2777,8 @@ run</programlisting>
|
|||||||
<title><varname>sndfile</varname></title>
|
<title><varname>sndfile</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes WAV and AIFF files using
|
Decodes WAV and AIFF files using <ulink
|
||||||
<filename>libsndfile</filename>.
|
url="http://www.mega-nerd.com/libsndfile/"><filename>libsndfile</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2658,8 +2786,8 @@ run</programlisting>
|
|||||||
<title><varname>vorbis</varname></title>
|
<title><varname>vorbis</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes Ogg-Vorbis files using
|
Decodes Ogg-Vorbis files using <ulink
|
||||||
<application>libvorbis</application>.
|
url="http://www.xiph.org/ogg/vorbis/"><application>libvorbis</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2668,7 +2796,7 @@ run</programlisting>
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes WavPack files using
|
Decodes WavPack files using
|
||||||
<application>libwavpack</application>.
|
<ulink url="http://www.wavpack.com/"><application>libwavpack</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2863,6 +2991,60 @@ run</programlisting>
|
|||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="opus_encoder">
|
||||||
|
<title><varname>opus</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Encodes into <ulink
|
||||||
|
url="http://www.opus-codec.org/">Ogg Opus</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Setting</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>bitrate</varname>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Sets the data rate in bit per second. The special
|
||||||
|
value "auto" lets <application>libopus</application>
|
||||||
|
choose a rate (which is the default), and "max" uses
|
||||||
|
the maximum possible data rate.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>complexity</varname>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Sets the <ulink
|
||||||
|
url="https://wiki.xiph.org/OpusFAQ#What_is_the_complexity_of_Opus.3F">Opus
|
||||||
|
complexity</ulink>.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>signal</varname>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Sets the Opus signal type. Valid values are "auto"
|
||||||
|
(the default), "voice" and "music".
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section id="vorbis_encoder">
|
<section id="vorbis_encoder">
|
||||||
<title><varname>vorbis</varname></title>
|
<title><varname>vorbis</varname></title>
|
||||||
|
|
||||||
@@ -2886,8 +3068,8 @@ run</programlisting>
|
|||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
Sets the quality for VBR. -1 is the lowest quality,
|
Sets the quality for VBR. -1 is the lowest quality,
|
||||||
10 is the highest quality. Cannot be used with
|
10 is the highest quality. Defaults to 3. Cannot
|
||||||
<varname>bitrate</varname>.
|
be used with <varname>bitrate</varname>.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
@@ -3492,7 +3674,7 @@ run</programlisting>
|
|||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section id="jack_output">
|
||||||
<title><varname>jack</varname></title>
|
<title><varname>jack</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -3772,7 +3954,7 @@ run</programlisting>
|
|||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section id="openal_output">
|
||||||
<title><varname>openal</varname></title>
|
<title><varname>openal</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -3923,7 +4105,7 @@ run</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
The <varname>pulse</varname> plugin connects to a <ulink
|
The <varname>pulse</varname> plugin connects to a <ulink
|
||||||
url="http://www.freedesktop.org/wiki/Software/PulseAudio/"><application>PulseAudio</application></ulink>
|
url="http://www.freedesktop.org/wiki/Software/PulseAudio/"><application>PulseAudio</application></ulink>
|
||||||
server.
|
server. Requires <filename>libpulse</filename>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informaltable>
|
<informaltable>
|
||||||
@@ -4111,7 +4293,8 @@ run</programlisting>
|
|||||||
url="http://www.shoutcast.com/"><application>ShoutCast</application></ulink>
|
url="http://www.shoutcast.com/"><application>ShoutCast</application></ulink>
|
||||||
or <ulink
|
or <ulink
|
||||||
url="http://icecast.org/"><application>IceCast</application></ulink>
|
url="http://icecast.org/"><application>IceCast</application></ulink>
|
||||||
server. It forwards tags to this server.
|
server using <filename>libshout</filename>. It forwards
|
||||||
|
tags to this server.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
29
python/build/cmdline.py
Normal file
29
python/build/cmdline.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
def concatenate_cmdline_variables(src, names):
|
||||||
|
"""Find duplicate variable declarations on the given source list, and
|
||||||
|
concatenate the values of those in the 'names' list."""
|
||||||
|
|
||||||
|
# the result list being constructed
|
||||||
|
dest = []
|
||||||
|
|
||||||
|
# a map of variable name to destination list index
|
||||||
|
positions = {}
|
||||||
|
|
||||||
|
for item in src:
|
||||||
|
i = item.find('=')
|
||||||
|
if i > 0:
|
||||||
|
# it's a variable
|
||||||
|
name = item[:i]
|
||||||
|
if name in names:
|
||||||
|
# it's a known variable
|
||||||
|
if name in positions:
|
||||||
|
# already specified: concatenate instead of
|
||||||
|
# appending it
|
||||||
|
dest[positions[name]] += ' ' + item[i + 1:]
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# not yet seen: append it and remember the list
|
||||||
|
# index
|
||||||
|
positions[name] = len(dest)
|
||||||
|
dest.append(item)
|
||||||
|
|
||||||
|
return dest
|
@@ -19,8 +19,8 @@ libvorbis = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
opus = AutotoolsProject(
|
opus = AutotoolsProject(
|
||||||
'http://downloads.xiph.org/releases/opus/opus-1.1.4.tar.gz',
|
'https://archive.mozilla.org/pub/opus/opus-1.2.1.tar.gz',
|
||||||
'9122b6b380081dd2665189f97bfd777f04f92dc3ab6698eea1dbb27ad59d8692',
|
'cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732',
|
||||||
'lib/libopus.a',
|
'lib/libopus.a',
|
||||||
['--disable-shared', '--enable-static'],
|
['--disable-shared', '--enable-static'],
|
||||||
)
|
)
|
||||||
@@ -57,9 +57,20 @@ libmad = AutotoolsProject(
|
|||||||
autogen=True,
|
autogen=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
liblame = AutotoolsProject(
|
||||||
|
'http://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz',
|
||||||
|
'24346b4158e4af3bd9f2e194bb23eb473c75fb7377011523353196b19b9a23ff',
|
||||||
|
'lib/libmp3lame.a',
|
||||||
|
[
|
||||||
|
'--disable-shared', '--enable-static',
|
||||||
|
'--disable-gtktest', '--disable-analyzer-hooks',
|
||||||
|
'--disable-decoder', '--disable-frontend',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
ffmpeg = FfmpegProject(
|
ffmpeg = FfmpegProject(
|
||||||
'http://ffmpeg.org/releases/ffmpeg-3.3.tar.xz',
|
'http://ffmpeg.org/releases/ffmpeg-3.3.3.tar.xz',
|
||||||
'599e7f7c017221c22011c4037b88bdcd1c47cd40c1e466838bc3c465f3e9569d',
|
'd2a9002cdc6b533b59728827186c044ad02ba64841f1b7cd6c21779875453a1e',
|
||||||
'lib/libavcodec.a',
|
'lib/libavcodec.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -82,8 +93,8 @@ ffmpeg = FfmpegProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
curl = AutotoolsProject(
|
curl = AutotoolsProject(
|
||||||
'http://curl.haxx.se/download/curl-7.54.0.tar.lzma',
|
'http://curl.haxx.se/download/curl-7.55.1.tar.xz',
|
||||||
'cd6aa6039f13e0b06e0a93e1b93754f6dc07f444812bb6c32be75a8f28c4070a',
|
'3eafca6e84ecb4af5f35795dee84e643d5428287e88c041122bb8dac18676bb7',
|
||||||
'lib/libcurl.a',
|
'lib/libcurl.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -103,7 +114,7 @@ curl = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
boost = BoostProject(
|
boost = BoostProject(
|
||||||
'http://downloads.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2',
|
'http://downloads.sourceforge.net/project/boost/boost/1.65.0/boost_1_65_0.tar.bz2',
|
||||||
'7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332',
|
'ea26712742e2fb079c2a566a31f3266973b76e38222b9f88b387e3c8b2f9902c',
|
||||||
'include/boost/version.hpp',
|
'include/boost/version.hpp',
|
||||||
)
|
)
|
||||||
|
@@ -127,7 +127,7 @@ struct AudioFormat {
|
|||||||
void ApplyMask(AudioFormat mask) noexcept;
|
void ApplyMask(AudioFormat mask) noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
AudioFormat WithMask(AudioFormat mask) const {
|
AudioFormat WithMask(AudioFormat mask) const noexcept {
|
||||||
AudioFormat result = *this;
|
AudioFormat result = *this;
|
||||||
result.ApplyMask(mask);
|
result.ApplyMask(mask);
|
||||||
return result;
|
return result;
|
||||||
|
@@ -152,7 +152,7 @@ public:
|
|||||||
bool IsRemote() const noexcept;
|
bool IsRemote() const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsFile() const {
|
bool IsFile() const noexcept {
|
||||||
return !IsRemote();
|
return !IsRemote();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,11 +162,11 @@ public:
|
|||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsInDatabase() const noexcept;
|
bool IsInDatabase() const noexcept;
|
||||||
|
|
||||||
const Tag &GetTag() const {
|
const Tag &GetTag() const noexcept {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tag &WritableTag() {
|
Tag &WritableTag() noexcept {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
src/Main.cxx
12
src/Main.cxx
@@ -121,8 +121,16 @@ static constexpr size_t KILOBYTE = 1024;
|
|||||||
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
|
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
|
||||||
|
|
||||||
static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
|
static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
|
||||||
static constexpr size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
|
|
||||||
64 * KILOBYTE);
|
static
|
||||||
|
#if GCC_OLDER_THAN(5,0)
|
||||||
|
/* gcc 4.x has no "constexpr" for std::max() */
|
||||||
|
const
|
||||||
|
#else
|
||||||
|
constexpr
|
||||||
|
#endif
|
||||||
|
size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
|
||||||
|
64 * KILOBYTE);
|
||||||
|
|
||||||
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
|
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
|
||||||
|
|
||||||
|
@@ -31,45 +31,45 @@ class MixRampInfo {
|
|||||||
public:
|
public:
|
||||||
MixRampInfo() = default;
|
MixRampInfo() = default;
|
||||||
|
|
||||||
void Clear() {
|
void Clear() noexcept {
|
||||||
start.clear();
|
start.clear();
|
||||||
end.clear();
|
end.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsDefined() const {
|
bool IsDefined() const noexcept {
|
||||||
return !start.empty() || !end.empty();
|
return !start.empty() || !end.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetStart() const {
|
const char *GetStart() const noexcept {
|
||||||
return start.empty() ? nullptr : start.c_str();
|
return start.empty() ? nullptr : start.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetEnd() const {
|
const char *GetEnd() const noexcept {
|
||||||
return end.empty() ? nullptr : end.c_str();
|
return end.empty() ? nullptr : end.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStart(const char *new_value) {
|
void SetStart(const char *new_value) noexcept {
|
||||||
if (new_value == nullptr)
|
if (new_value == nullptr)
|
||||||
start.clear();
|
start.clear();
|
||||||
else
|
else
|
||||||
start = new_value;
|
start = new_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStart(std::string &&new_value) {
|
void SetStart(std::string &&new_value) noexcept {
|
||||||
start = std::move(new_value);
|
start = std::move(new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEnd(const char *new_value) {
|
void SetEnd(const char *new_value) noexcept {
|
||||||
if (new_value == nullptr)
|
if (new_value == nullptr)
|
||||||
end.clear();
|
end.clear();
|
||||||
else
|
else
|
||||||
end = new_value;
|
end = new_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEnd(std::string &&new_value) {
|
void SetEnd(std::string &&new_value) noexcept {
|
||||||
end = std::move(new_value);
|
end = std::move(new_value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -60,7 +60,7 @@ public:
|
|||||||
* music_buffer_new().
|
* music_buffer_new().
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
unsigned GetSize() const {
|
unsigned GetSize() const noexcept {
|
||||||
return buffer.GetCapacity();
|
return buffer.GetCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ MusicPipe::Contains(const MusicChunk *chunk) const noexcept
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
MusicChunk *
|
MusicChunk *
|
||||||
MusicPipe::Shift()
|
MusicPipe::Shift() noexcept
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ MusicPipe::Shift()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MusicPipe::Clear(MusicBuffer &buffer)
|
MusicPipe::Clear(MusicBuffer &buffer) noexcept
|
||||||
{
|
{
|
||||||
MusicChunk *chunk;
|
MusicChunk *chunk;
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ MusicPipe::Clear(MusicBuffer &buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MusicPipe::Push(MusicChunk *chunk)
|
MusicPipe::Push(MusicChunk *chunk) noexcept
|
||||||
{
|
{
|
||||||
assert(!chunk->IsEmpty());
|
assert(!chunk->IsEmpty());
|
||||||
assert(chunk->length == 0 || chunk->audio_format.IsValid());
|
assert(chunk->length == 0 || chunk->audio_format.IsValid());
|
||||||
|
@@ -77,7 +77,7 @@ public:
|
|||||||
* audio_format.
|
* audio_format.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool CheckFormat(AudioFormat other) const {
|
bool CheckFormat(AudioFormat other) const noexcept {
|
||||||
return !audio_format.IsDefined() ||
|
return !audio_format.IsDefined() ||
|
||||||
audio_format == other;
|
audio_format == other;
|
||||||
}
|
}
|
||||||
@@ -94,37 +94,37 @@ public:
|
|||||||
* nullptr if the pipe is empty.
|
* nullptr if the pipe is empty.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const MusicChunk *Peek() const {
|
const MusicChunk *Peek() const noexcept {
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the first chunk from the head, and returns it.
|
* Removes the first chunk from the head, and returns it.
|
||||||
*/
|
*/
|
||||||
MusicChunk *Shift();
|
MusicChunk *Shift() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the whole pipe and returns the chunks to the buffer.
|
* Clears the whole pipe and returns the chunks to the buffer.
|
||||||
*
|
*
|
||||||
* @param buffer the buffer object to return the chunks to
|
* @param buffer the buffer object to return the chunks to
|
||||||
*/
|
*/
|
||||||
void Clear(MusicBuffer &buffer);
|
void Clear(MusicBuffer &buffer) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes a chunk to the tail of the pipe.
|
* Pushes a chunk to the tail of the pipe.
|
||||||
*/
|
*/
|
||||||
void Push(MusicChunk *chunk);
|
void Push(MusicChunk *chunk) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of chunks currently in this pipe.
|
* Returns the number of chunks currently in this pipe.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
unsigned GetSize() const {
|
unsigned GetSize() const noexcept {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const noexcept {
|
||||||
return GetSize() == 0;
|
return GetSize() == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -207,13 +207,12 @@ try {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
#ifdef _UNICODE
|
#ifdef _UNICODE
|
||||||
wchar_t buffer[MAX_PATH];
|
/* on Windows, playlists always contain UTF-8, because
|
||||||
auto result = MultiByteToWideChar(CP_ACP, 0, s, -1,
|
its "narrow" charset (i.e. CP_ACP) is incapable of
|
||||||
buffer, ARRAY_SIZE(buffer));
|
storing all Unicode paths */
|
||||||
if (result <= 0)
|
const auto path = AllocatedPath::FromUTF8(s);
|
||||||
|
if (path.IsNull())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Path path = Path::FromFS(buffer);
|
|
||||||
#else
|
#else
|
||||||
const Path path = Path::FromFS(s);
|
const Path path = Path::FromFS(s);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -28,13 +28,25 @@
|
|||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
#include "fs/NarrowPath.hxx"
|
|
||||||
#include "fs/io/FileOutputStream.hxx"
|
#include "fs/io/FileOutputStream.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "fs/io/BufferedOutputStream.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
static void
|
||||||
|
playlist_print_path(BufferedOutputStream &os, const Path path)
|
||||||
|
{
|
||||||
|
#ifdef _UNICODE
|
||||||
|
/* on Windows, playlists always contain UTF-8, because its
|
||||||
|
"narrow" charset (i.e. CP_ACP) is incapable of storing all
|
||||||
|
Unicode paths */
|
||||||
|
os.Format("%s\n", path.ToUTF8().c_str());
|
||||||
|
#else
|
||||||
|
os.Format("%s\n", path.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
|
playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
|
||||||
{
|
{
|
||||||
@@ -44,7 +56,7 @@ playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const auto uri_fs = AllocatedPath::FromUTF8Throw(uri_utf8);
|
const auto uri_fs = AllocatedPath::FromUTF8Throw(uri_utf8);
|
||||||
os.Format("%s\n", NarrowPath(uri_fs).c_str());
|
playlist_print_path(os, uri_fs);
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,7 +75,7 @@ playlist_print_uri(BufferedOutputStream &os, const char *uri)
|
|||||||
AllocatedPath::FromUTF8Throw(uri);
|
AllocatedPath::FromUTF8Throw(uri);
|
||||||
|
|
||||||
if (!path.IsNull())
|
if (!path.IsNull())
|
||||||
os.Format("%s\n", NarrowPath(path).c_str());
|
playlist_print_path(os, path);
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/TimeParser.hxx"
|
#include "util/TimeParser.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
#include "lib/icu/Collate.hxx"
|
#include "lib/icu/CaseFold.hxx"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@@ -57,17 +57,10 @@ locate_parse_type(const char *str) noexcept
|
|||||||
return tag_name_parse_i(str);
|
return tag_name_parse_i(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AllocatedString<>
|
|
||||||
ImportString(const char *p, bool fold_case)
|
|
||||||
{
|
|
||||||
return fold_case
|
|
||||||
? IcuCaseFold(p)
|
|
||||||
: AllocatedString<>::Duplicate(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
|
SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
|
||||||
:tag(_tag), fold_case(_fold_case),
|
:tag(_tag),
|
||||||
value(ImportString(_value, _fold_case))
|
value(AllocatedString<>::Duplicate(_value)),
|
||||||
|
fold_case(_fold_case ? IcuCompare(value.c_str()) : IcuCompare())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,9 +80,7 @@ SongFilter::Item::StringMatch(const char *s) const noexcept
|
|||||||
assert(tag != LOCATE_TAG_MODIFIED_SINCE);
|
assert(tag != LOCATE_TAG_MODIFIED_SINCE);
|
||||||
|
|
||||||
if (fold_case) {
|
if (fold_case) {
|
||||||
const auto folded = IcuCaseFold(s);
|
return fold_case.IsIn(s);
|
||||||
assert(!folded.IsNull());
|
|
||||||
return StringFind(folded.c_str(), value.c_str()) != nullptr;
|
|
||||||
} else {
|
} else {
|
||||||
return StringIsEqual(s, value.c_str());
|
return StringIsEqual(s, value.c_str());
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#ifndef MPD_SONG_FILTER_HXX
|
#ifndef MPD_SONG_FILTER_HXX
|
||||||
#define MPD_SONG_FILTER_HXX
|
#define MPD_SONG_FILTER_HXX
|
||||||
|
|
||||||
|
#include "lib/icu/Compare.hxx"
|
||||||
#include "util/AllocatedString.hxx"
|
#include "util/AllocatedString.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
@@ -48,10 +49,13 @@ public:
|
|||||||
class Item {
|
class Item {
|
||||||
uint8_t tag;
|
uint8_t tag;
|
||||||
|
|
||||||
bool fold_case;
|
|
||||||
|
|
||||||
AllocatedString<> value;
|
AllocatedString<> value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value is only set if case folding is enabled.
|
||||||
|
*/
|
||||||
|
IcuCompare fold_case;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For #LOCATE_TAG_MODIFIED_SINCE
|
* For #LOCATE_TAG_MODIFIED_SINCE
|
||||||
*/
|
*/
|
||||||
|
@@ -100,7 +100,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsExpired() const {
|
bool IsExpired() const noexcept {
|
||||||
return !FullyBufferedSocket::IsDefined();
|
return !FullyBufferedSocket::IsDefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,68 +45,57 @@ public:
|
|||||||
: default_value;
|
: default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseInt(unsigned idx) const {
|
int ParseInt(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgInt(data[idx]);
|
return ParseCommandArgInt(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseInt(unsigned idx, int min_value, int max_value) const {
|
int ParseInt(unsigned idx, int min_value, int max_value) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgInt(data[idx], min_value, max_value);
|
return ParseCommandArgInt(data[idx], min_value, max_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseUnsigned(unsigned idx) const {
|
int ParseUnsigned(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgUnsigned(data[idx]);
|
return ParseCommandArgUnsigned(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseUnsigned(unsigned idx, unsigned max_value) const {
|
int ParseUnsigned(unsigned idx, unsigned max_value) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgUnsigned(data[idx], max_value);
|
return ParseCommandArgUnsigned(data[idx], max_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
bool ParseBool(unsigned idx) const {
|
bool ParseBool(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgBool(data[idx]);
|
return ParseCommandArgBool(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
RangeArg ParseRange(unsigned idx) const {
|
RangeArg ParseRange(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgRange(data[idx]);
|
return ParseCommandArgRange(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
float ParseFloat(unsigned idx) const {
|
float ParseFloat(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgFloat(data[idx]);
|
return ParseCommandArgFloat(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
SongTime ParseSongTime(unsigned idx) const {
|
SongTime ParseSongTime(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgSongTime(data[idx]);
|
return ParseCommandArgSongTime(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
SignedSongTime ParseSignedSongTime(unsigned idx) const {
|
SignedSongTime ParseSignedSongTime(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgSignedSongTime(data[idx]);
|
return ParseCommandArgSignedSongTime(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseOptional(unsigned idx, int default_value) const {
|
int ParseOptional(unsigned idx, int default_value) const {
|
||||||
return idx < size
|
return idx < size
|
||||||
? ParseInt(idx)
|
? ParseInt(idx)
|
||||||
: default_value;
|
: default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
RangeArg ParseOptional(unsigned idx, RangeArg default_value) const {
|
RangeArg ParseOptional(unsigned idx, RangeArg default_value) const {
|
||||||
return idx < size
|
return idx < size
|
||||||
? ParseRange(idx)
|
? ParseRange(idx)
|
||||||
|
@@ -82,12 +82,12 @@ struct ConfigBlock {
|
|||||||
* object that was synthesized and not loaded from a
|
* object that was synthesized and not loaded from a
|
||||||
* configuration file.
|
* configuration file.
|
||||||
*/
|
*/
|
||||||
bool IsNull() const {
|
bool IsNull() const noexcept {
|
||||||
return line < 0;
|
return line < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const noexcept {
|
||||||
return block_params.empty();
|
return block_params.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
struct StringLess {
|
struct StringLess {
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator()(const char *a, const char *b) const {
|
bool operator()(const char *a, const char *b) const noexcept {
|
||||||
return strcmp(a, b) < 0;
|
return strcmp(a, b) < 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -106,7 +106,6 @@ public:
|
|||||||
TagType tag_type, tag_mask_t group_mask,
|
TagType tag_type, tag_mask_t group_mask,
|
||||||
VisitTag visit_tag) const = 0;
|
VisitTag visit_tag) const = 0;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
virtual DatabaseStats GetStats(const DatabaseSelection &selection) const = 0;
|
virtual DatabaseStats GetStats(const DatabaseSelection &selection) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,7 +126,7 @@ public:
|
|||||||
* Returns 0 if that is not not known/available.
|
* Returns 0 if that is not not known/available.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
virtual time_t GetUpdateStamp() const = 0;
|
virtual time_t GetUpdateStamp() const noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -44,16 +44,16 @@ struct LightDirectory {
|
|||||||
constexpr LightDirectory(const char *_uri, time_t _mtime)
|
constexpr LightDirectory(const char *_uri, time_t _mtime)
|
||||||
:uri(_uri), mtime(_mtime) {}
|
:uri(_uri), mtime(_mtime) {}
|
||||||
|
|
||||||
static constexpr LightDirectory Root() {
|
static constexpr LightDirectory Root() noexcept {
|
||||||
return LightDirectory("", 0);
|
return LightDirectory("", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRoot() const {
|
bool IsRoot() const noexcept {
|
||||||
return *uri == 0;
|
return *uri == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetPath() const {
|
const char *GetPath() const noexcept {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -45,7 +45,7 @@ struct PlaylistInfo {
|
|||||||
constexpr CompareName(const char *_name):name(_name) {}
|
constexpr CompareName(const char *_name):name(_name) {}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator()(const PlaylistInfo &pi) const {
|
bool operator()(const PlaylistInfo &pi) const noexcept {
|
||||||
return pi.name.compare(name) == 0;
|
return pi.name.compare(name) == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "Selection.hxx"
|
#include "Selection.hxx"
|
||||||
#include "SongFilter.hxx"
|
#include "SongFilter.hxx"
|
||||||
|
|
||||||
|
@@ -127,7 +127,7 @@ public:
|
|||||||
|
|
||||||
unsigned Update(const char *uri_utf8, bool discard) override;
|
unsigned Update(const char *uri_utf8, bool discard) override;
|
||||||
|
|
||||||
time_t GetUpdateStamp() const override {
|
time_t GetUpdateStamp() const noexcept override {
|
||||||
return update_stamp;
|
return update_stamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -187,7 +187,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetPath() const {
|
const char *GetPath() const noexcept {
|
||||||
return path.c_str();
|
return path.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -76,7 +76,7 @@ public:
|
|||||||
const ConfigBlock &block);
|
const ConfigBlock &block);
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
Directory &GetRoot() {
|
Directory &GetRoot() noexcept {
|
||||||
assert(root != NULL);
|
assert(root != NULL);
|
||||||
|
|
||||||
return *root;
|
return *root;
|
||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
|
|
||||||
DatabaseStats GetStats(const DatabaseSelection &selection) const override;
|
DatabaseStats GetStats(const DatabaseSelection &selection) const override;
|
||||||
|
|
||||||
time_t GetUpdateStamp() const override {
|
time_t GetUpdateStamp() const noexcept override {
|
||||||
return mtime;
|
return mtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -60,7 +60,7 @@ public:
|
|||||||
* Parent's ObjectId
|
* Parent's ObjectId
|
||||||
*/
|
*/
|
||||||
std::string parent_id;
|
std::string parent_id;
|
||||||
|
|
||||||
std::string url;
|
std::string url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
|
|
||||||
UPnPDirObject &operator=(UPnPDirObject &&) = default;
|
UPnPDirObject &operator=(UPnPDirObject &&) = default;
|
||||||
|
|
||||||
void Clear() {
|
void Clear() noexcept {
|
||||||
id.clear();
|
id.clear();
|
||||||
parent_id.clear();
|
parent_id.clear();
|
||||||
url.clear();
|
url.clear();
|
||||||
@@ -90,7 +90,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Check() const {
|
bool Check() const noexcept {
|
||||||
return !id.empty() && !parent_id.empty() && !name.empty() &&
|
return !id.empty() && !parent_id.empty() && !name.empty() &&
|
||||||
(type != UPnPDirObject::Type::ITEM ||
|
(type != UPnPDirObject::Type::ITEM ||
|
||||||
item_class != UPnPDirObject::ItemClass::UNKNOWN);
|
item_class != UPnPDirObject::ItemClass::UNKNOWN);
|
||||||
|
@@ -93,7 +93,7 @@ public:
|
|||||||
|
|
||||||
DatabaseStats GetStats(const DatabaseSelection &selection) const override;
|
DatabaseStats GetStats(const DatabaseSelection &selection) const override;
|
||||||
|
|
||||||
time_t GetUpdateStamp() const override {
|
time_t GetUpdateStamp() const noexcept override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,7 +36,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ExcludeList::LoadFile(Path path_fs)
|
ExcludeList::LoadFile(Path path_fs) noexcept
|
||||||
try {
|
try {
|
||||||
#ifdef HAVE_CLASS_GLOB
|
#ifdef HAVE_CLASS_GLOB
|
||||||
TextFile file(path_fs);
|
TextFile file(path_fs);
|
||||||
@@ -67,7 +67,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ExcludeList::Check(Path name_fs) const
|
ExcludeList::Check(Path name_fs) const noexcept
|
||||||
{
|
{
|
||||||
assert(!name_fs.IsNull());
|
assert(!name_fs.IsNull());
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@ public:
|
|||||||
:parent(&_parent) {}
|
:parent(&_parent) {}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const noexcept {
|
||||||
#ifdef HAVE_CLASS_GLOB
|
#ifdef HAVE_CLASS_GLOB
|
||||||
return ((parent == nullptr) || parent->IsEmpty()) && patterns.empty();
|
return ((parent == nullptr) || parent->IsEmpty()) && patterns.empty();
|
||||||
#else
|
#else
|
||||||
@@ -62,13 +62,13 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Loads and parses a .mpdignore file.
|
* Loads and parses a .mpdignore file.
|
||||||
*/
|
*/
|
||||||
bool LoadFile(Path path_fs);
|
bool LoadFile(Path path_fs) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether one of the patterns in the .mpdignore file matches
|
* Checks whether one of the patterns in the .mpdignore file matches
|
||||||
* the specified file name.
|
* the specified file name.
|
||||||
*/
|
*/
|
||||||
bool Check(Path name_fs) const;
|
bool Check(Path name_fs) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -277,7 +277,7 @@ DecoderBridge::Ready(const AudioFormat audio_format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DecoderCommand
|
DecoderCommand
|
||||||
DecoderBridge::GetCommand()
|
DecoderBridge::GetCommand() noexcept
|
||||||
{
|
{
|
||||||
return LockGetVirtualCommand();
|
return LockGetVirtualCommand();
|
||||||
}
|
}
|
||||||
@@ -326,7 +326,7 @@ DecoderBridge::CommandFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SongTime
|
SongTime
|
||||||
DecoderBridge::GetSeekTime()
|
DecoderBridge::GetSeekTime() noexcept
|
||||||
{
|
{
|
||||||
assert(dc.pipe != nullptr);
|
assert(dc.pipe != nullptr);
|
||||||
|
|
||||||
@@ -341,7 +341,7 @@ DecoderBridge::GetSeekTime()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t
|
uint64_t
|
||||||
DecoderBridge::GetSeekFrame()
|
DecoderBridge::GetSeekFrame() noexcept
|
||||||
{
|
{
|
||||||
return GetSeekTime().ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
return GetSeekTime().ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
||||||
}
|
}
|
||||||
|
@@ -134,10 +134,10 @@ public:
|
|||||||
/* virtual methods from DecoderClient */
|
/* virtual methods from DecoderClient */
|
||||||
void Ready(AudioFormat audio_format,
|
void Ready(AudioFormat audio_format,
|
||||||
bool seekable, SignedSongTime duration) override;
|
bool seekable, SignedSongTime duration) override;
|
||||||
DecoderCommand GetCommand() override;
|
DecoderCommand GetCommand() noexcept override;
|
||||||
void CommandFinished() override;
|
void CommandFinished() override;
|
||||||
SongTime GetSeekTime() override;
|
SongTime GetSeekTime() noexcept override;
|
||||||
uint64_t GetSeekFrame() override;
|
uint64_t GetSeekFrame() noexcept override;
|
||||||
void SeekError() override;
|
void SeekError() override;
|
||||||
InputStreamPtr OpenUri(const char *uri) override;
|
InputStreamPtr OpenUri(const char *uri) override;
|
||||||
size_t Read(InputStream &is, void *buffer, size_t length) override;
|
size_t Read(InputStream &is, void *buffer, size_t length) override;
|
||||||
|
@@ -58,7 +58,7 @@ public:
|
|||||||
* command pending
|
* command pending
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
virtual DecoderCommand GetCommand() = 0;
|
virtual DecoderCommand GetCommand() noexcept = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the decoder when it has performed the requested command
|
* Called by the decoder when it has performed the requested command
|
||||||
@@ -73,7 +73,7 @@ public:
|
|||||||
* @return the destination position for the seek in milliseconds
|
* @return the destination position for the seek in milliseconds
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
virtual SongTime GetSeekTime() = 0;
|
virtual SongTime GetSeekTime() noexcept = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this when you have received the DecoderCommand::SEEK command.
|
* Call this when you have received the DecoderCommand::SEEK command.
|
||||||
@@ -81,7 +81,7 @@ public:
|
|||||||
* @return the destination position for the seek in frames
|
* @return the destination position for the seek in frames
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
virtual uint64_t GetSeekFrame() = 0;
|
virtual uint64_t GetSeekFrame() noexcept = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this instead of CommandFinished() when seeking has
|
* Call this instead of CommandFinished() when seeking has
|
||||||
|
@@ -54,11 +54,11 @@ public:
|
|||||||
size_t _size)
|
size_t _size)
|
||||||
:client(_client), is(_is), buffer(_size) {}
|
:client(_client), is(_is), buffer(_size) {}
|
||||||
|
|
||||||
const InputStream &GetStream() const {
|
const InputStream &GetStream() const noexcept {
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear() {
|
void Clear() noexcept {
|
||||||
buffer.Clear();
|
buffer.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ public:
|
|||||||
* How many bytes are stored in the buffer?
|
* How many bytes are stored in the buffer?
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
size_t GetAvailable() const {
|
size_t GetAvailable() const noexcept {
|
||||||
return buffer.GetAvailable();
|
return buffer.GetAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ public:
|
|||||||
* you have to call Consume() to do that. The returned buffer
|
* you have to call Consume() to do that. The returned buffer
|
||||||
* becomes invalid after a Fill() or a Consume() call.
|
* becomes invalid after a Fill() or a Consume() call.
|
||||||
*/
|
*/
|
||||||
ConstBuffer<void> Read() const {
|
ConstBuffer<void> Read() const noexcept {
|
||||||
auto r = buffer.Read();
|
auto r = buffer.Read();
|
||||||
return { r.data, r.size };
|
return { r.data, r.size };
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param nbytes the number of bytes to consume
|
* @param nbytes the number of bytes to consume
|
||||||
*/
|
*/
|
||||||
void Consume(size_t nbytes) {
|
void Consume(size_t nbytes) noexcept {
|
||||||
buffer.Consume(nbytes);
|
buffer.Consume(nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -227,29 +227,29 @@ struct DecoderControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool LockIsIdle() const {
|
bool LockIsIdle() const noexcept {
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
return IsIdle();
|
return IsIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsStarting() const {
|
bool IsStarting() const noexcept {
|
||||||
return state == DecoderState::START;
|
return state == DecoderState::START;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool LockIsStarting() const {
|
bool LockIsStarting() const noexcept {
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
return IsStarting();
|
return IsStarting();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasFailed() const {
|
bool HasFailed() const noexcept {
|
||||||
assert(command == DecoderCommand::NONE);
|
assert(command == DecoderCommand::NONE);
|
||||||
|
|
||||||
return state == DecoderState::ERROR;
|
return state == DecoderState::ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool LockHasFailed() const {
|
bool LockHasFailed() const noexcept {
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
return HasFailed();
|
return HasFailed();
|
||||||
}
|
}
|
||||||
|
@@ -508,6 +508,7 @@ try {
|
|||||||
decoder_run_song(dc, song, uri_utf8, path_fs);
|
decoder_run_song(dc, song, uri_utf8, path_fs);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
dc.state = DecoderState::ERROR;
|
dc.state = DecoderState::ERROR;
|
||||||
|
dc.command = DecoderCommand::NONE;
|
||||||
dc.error = std::current_exception();
|
dc.error = std::current_exception();
|
||||||
dc.client_cond.signal();
|
dc.client_cond.signal();
|
||||||
}
|
}
|
||||||
|
@@ -258,7 +258,7 @@ FfmpegSendFrame(DecoderClient &client, InputStream &is,
|
|||||||
try {
|
try {
|
||||||
output_buffer = copy_interleave_frame(codec_context, frame,
|
output_buffer = copy_interleave_frame(codec_context, frame,
|
||||||
buffer);
|
buffer);
|
||||||
} catch (const std::exception e) {
|
} catch (const std::exception &e) {
|
||||||
/* this must be a serious error, e.g. OOM */
|
/* this must be a serious error, e.g. OOM */
|
||||||
LogError(e);
|
LogError(e);
|
||||||
return DecoderCommand::STOP;
|
return DecoderCommand::STOP;
|
||||||
@@ -712,7 +712,9 @@ FfmpegDecode(DecoderClient &client, InputStream &input,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
const SignedSongTime total_time =
|
const SignedSongTime total_time =
|
||||||
FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base);
|
av_stream.duration != (int64_t)AV_NOPTS_VALUE
|
||||||
|
? FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base)
|
||||||
|
: FromFfmpegTimeChecked(format_context.duration, AV_TIME_BASE_Q);
|
||||||
|
|
||||||
client.Ready(audio_format, input.IsSeekable(), total_time);
|
client.Ready(audio_format, input.IsSeekable(), total_time);
|
||||||
|
|
||||||
@@ -842,6 +844,10 @@ FfmpegScanStream(AVFormatContext &format_context,
|
|||||||
tag_handler_invoke_duration(handler, handler_ctx,
|
tag_handler_invoke_duration(handler, handler_ctx,
|
||||||
FromFfmpegTime(stream.duration,
|
FromFfmpegTime(stream.duration,
|
||||||
stream.time_base));
|
stream.time_base));
|
||||||
|
else if (format_context.duration != (int64_t)AV_NOPTS_VALUE)
|
||||||
|
tag_handler_invoke_duration(handler, handler_ctx,
|
||||||
|
FromFfmpegTime(format_context.duration,
|
||||||
|
AV_TIME_BASE_Q));
|
||||||
|
|
||||||
FfmpegScanMetadata(format_context, audio_stream, handler, handler_ctx);
|
FfmpegScanMetadata(format_context, audio_stream, handler, handler_ctx);
|
||||||
|
|
||||||
@@ -881,7 +887,8 @@ ffmpeg_scan_stream(InputStream &is,
|
|||||||
* more formats.
|
* more formats.
|
||||||
*/
|
*/
|
||||||
static const char *const ffmpeg_suffixes[] = {
|
static const char *const ffmpeg_suffixes[] = {
|
||||||
"16sv", "3g2", "3gp", "4xm", "8svx", "aa3", "aac", "ac3", "afc", "aif",
|
"16sv", "3g2", "3gp", "4xm", "8svx",
|
||||||
|
"aa3", "aac", "ac3", "adx", "afc", "aif",
|
||||||
"aifc", "aiff", "al", "alaw", "amr", "anim", "apc", "ape", "asf",
|
"aifc", "aiff", "al", "alaw", "amr", "anim", "apc", "ape", "asf",
|
||||||
"atrac", "au", "aud", "avi", "avm2", "avs", "bap", "bfi", "c93", "cak",
|
"atrac", "au", "aud", "avi", "avm2", "avs", "bap", "bfi", "c93", "cak",
|
||||||
"cin", "cmv", "cpk", "daud", "dct", "divx", "dts", "dv", "dvd", "dxa",
|
"cin", "cmv", "cpk", "daud", "dct", "divx", "dts", "dv", "dvd", "dxa",
|
||||||
@@ -934,6 +941,7 @@ static const char *const ffmpeg_mime_types[] = {
|
|||||||
"audio/x-16sv",
|
"audio/x-16sv",
|
||||||
"audio/x-aac",
|
"audio/x-aac",
|
||||||
"audio/x-ac3",
|
"audio/x-ac3",
|
||||||
|
"audio/x-adx",
|
||||||
"audio/x-aiff"
|
"audio/x-aiff"
|
||||||
"audio/x-alaw",
|
"audio/x-alaw",
|
||||||
"audio/x-au",
|
"audio/x-au",
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include "FfmpegMetaData.hxx"
|
#include "FfmpegMetaData.hxx"
|
||||||
#include "tag/TagTable.hxx"
|
#include "tag/TagTable.hxx"
|
||||||
#include "tag/TagHandler.hxx"
|
#include "tag/TagHandler.hxx"
|
||||||
|
#include "tag/Id3MusicBrainz.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavutil/dict.h>
|
#include <libavutil/dict.h>
|
||||||
@@ -75,6 +76,11 @@ FfmpegScanDictionary(AVDictionary *dict,
|
|||||||
i->name != nullptr; ++i)
|
i->name != nullptr; ++i)
|
||||||
FfmpegScanTag(i->type, dict, i->name,
|
FfmpegScanTag(i->type, dict, i->name,
|
||||||
handler, handler_ctx);
|
handler, handler_ctx);
|
||||||
|
|
||||||
|
for (const struct tag_table *i = musicbrainz_txxx_tags;
|
||||||
|
i->name != nullptr; ++i)
|
||||||
|
FfmpegScanTag(i->type, dict, i->name,
|
||||||
|
handler, handler_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handler.pair != nullptr)
|
if (handler.pair != nullptr)
|
||||||
|
@@ -42,25 +42,27 @@ public:
|
|||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Read(const char *path) {
|
bool Read(const char *path) noexcept {
|
||||||
return ::FLAC__metadata_chain_read(chain, path);
|
return ::FLAC__metadata_chain_read(chain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Read(FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) {
|
bool Read(FLAC__IOHandle handle,
|
||||||
|
FLAC__IOCallbacks callbacks) noexcept {
|
||||||
return ::FLAC__metadata_chain_read_with_callbacks(chain,
|
return ::FLAC__metadata_chain_read_with_callbacks(chain,
|
||||||
handle,
|
handle,
|
||||||
callbacks);
|
callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Read(InputStream &is) {
|
bool Read(InputStream &is) noexcept {
|
||||||
return Read(::ToFlacIOHandle(is), ::GetFlacIOCallbacks(is));
|
return Read(::ToFlacIOHandle(is), ::GetFlacIOCallbacks(is));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadOgg(const char *path) {
|
bool ReadOgg(const char *path) noexcept {
|
||||||
return ::FLAC__metadata_chain_read_ogg(chain, path);
|
return ::FLAC__metadata_chain_read_ogg(chain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadOgg(FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) {
|
bool ReadOgg(FLAC__IOHandle handle,
|
||||||
|
FLAC__IOCallbacks callbacks) noexcept {
|
||||||
return ::FLAC__metadata_chain_read_ogg_with_callbacks(chain,
|
return ::FLAC__metadata_chain_read_ogg_with_callbacks(chain,
|
||||||
handle,
|
handle,
|
||||||
callbacks);
|
callbacks);
|
||||||
@@ -71,12 +73,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
FLAC__Metadata_ChainStatus GetStatus() const {
|
FLAC__Metadata_ChainStatus GetStatus() const noexcept {
|
||||||
return ::FLAC__metadata_chain_status(chain);
|
return ::FLAC__metadata_chain_status(chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetStatusString() const {
|
const char *GetStatusString() const noexcept {
|
||||||
return FLAC__Metadata_ChainStatusString[GetStatus()];
|
return FLAC__Metadata_ChainStatusString[GetStatus()];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,12 +101,12 @@ public:
|
|||||||
::FLAC__metadata_iterator_delete(iterator);
|
::FLAC__metadata_iterator_delete(iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Next() {
|
bool Next() noexcept {
|
||||||
return ::FLAC__metadata_iterator_next(iterator);
|
return ::FLAC__metadata_iterator_next(iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
FLAC__StreamMetadata *GetBlock() {
|
FLAC__StreamMetadata *GetBlock() noexcept {
|
||||||
return ::FLAC__metadata_iterator_get_block(iterator);
|
return ::FLAC__metadata_iterator_get_block(iterator);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -293,13 +293,13 @@ gme_container_scan(Path path_fs)
|
|||||||
TagBuilder tag_builder;
|
TagBuilder tag_builder;
|
||||||
|
|
||||||
auto tail = list.before_begin();
|
auto tail = list.before_begin();
|
||||||
for (unsigned i = 1; i <= num_songs; ++i) {
|
for (unsigned i = 0; i < num_songs; ++i) {
|
||||||
ScanMusicEmu(emu, i,
|
ScanMusicEmu(emu, i,
|
||||||
add_tag_handler, &tag_builder);
|
add_tag_handler, &tag_builder);
|
||||||
|
|
||||||
char track_name[64];
|
char track_name[64];
|
||||||
snprintf(track_name, sizeof(track_name),
|
snprintf(track_name, sizeof(track_name),
|
||||||
SUBTUNE_PREFIX "%03u.%s", i, subtune_suffix);
|
SUBTUNE_PREFIX "%03u.%s", i+1, subtune_suffix);
|
||||||
tail = list.emplace_after(tail, track_name,
|
tail = list.emplace_after(tail, track_name,
|
||||||
tag_builder.Commit());
|
tag_builder.Commit());
|
||||||
}
|
}
|
||||||
|
@@ -52,14 +52,14 @@ static constexpr unsigned opus_output_buffer_frames = opus_sample_rate / 4;
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
IsOpusHead(const ogg_packet &packet)
|
IsOpusHead(const ogg_packet &packet) noexcept
|
||||||
{
|
{
|
||||||
return packet.bytes >= 8 && memcmp(packet.packet, "OpusHead", 8) == 0;
|
return packet.bytes >= 8 && memcmp(packet.packet, "OpusHead", 8) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
IsOpusTags(const ogg_packet &packet)
|
IsOpusTags(const ogg_packet &packet) noexcept
|
||||||
{
|
{
|
||||||
return packet.bytes >= 8 && memcmp(packet.packet, "OpusTags", 8) == 0;
|
return packet.bytes >= 8 && memcmp(packet.packet, "OpusTags", 8) == 0;
|
||||||
}
|
}
|
||||||
|
@@ -178,6 +178,20 @@ VorbisDecoder::SubmitInit()
|
|||||||
client.Ready(audio_format, eos_granulepos > 0, duration);
|
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
|
bool
|
||||||
VorbisDecoder::SubmitSomePcm()
|
VorbisDecoder::SubmitSomePcm()
|
||||||
{
|
{
|
||||||
@@ -197,7 +211,7 @@ VorbisDecoder::SubmitSomePcm()
|
|||||||
auto *dest = &buffer[c];
|
auto *dest = &buffer[c];
|
||||||
|
|
||||||
for (size_t i = 0; i < n_frames; ++i) {
|
for (size_t i = 0; i < n_frames; ++i) {
|
||||||
*dest = *src++;
|
*dest = tremor_clip_sample(*src++);
|
||||||
dest += channels;
|
dest += channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,7 +62,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class PreparedVorbisEncoder final : public PreparedEncoder {
|
class PreparedVorbisEncoder final : public PreparedEncoder {
|
||||||
float quality;
|
float quality = 3;
|
||||||
int bitrate;
|
int bitrate;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -97,7 +97,7 @@ PreparedVorbisEncoder::PreparedVorbisEncoder(const ConfigBlock &block)
|
|||||||
|
|
||||||
value = block.GetBlockValue("bitrate");
|
value = block.GetBlockValue("bitrate");
|
||||||
if (value == nullptr)
|
if (value == nullptr)
|
||||||
throw std::runtime_error("neither bitrate nor quality defined");
|
return;
|
||||||
|
|
||||||
quality = -2.0;
|
quality = -2.0;
|
||||||
|
|
||||||
|
@@ -199,7 +199,7 @@ public:
|
|||||||
* Are we currently running inside this EventLoop's thread?
|
* Are we currently running inside this EventLoop's thread?
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsInside() const {
|
bool IsInside() const noexcept {
|
||||||
assert(!thread.IsNull());
|
assert(!thread.IsNull());
|
||||||
|
|
||||||
return thread.IsInside();
|
return thread.IsInside();
|
||||||
@@ -207,7 +207,7 @@ public:
|
|||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsInsideOrVirgin() const {
|
bool IsInsideOrVirgin() const noexcept {
|
||||||
return virgin || IsInside();
|
return virgin || IsInside();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -219,7 +219,7 @@ public:
|
|||||||
* are not yet/anymore handled.
|
* are not yet/anymore handled.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsInsideOrNull() const {
|
bool IsInsideOrNull() const noexcept {
|
||||||
return thread.IsNull() || thread.IsInside();
|
return thread.IsNull() || thread.IsInside();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -77,12 +77,12 @@ public:
|
|||||||
* @see IsNull()
|
* @see IsNull()
|
||||||
*/
|
*/
|
||||||
gcc_const
|
gcc_const
|
||||||
static AllocatedPath Null() {
|
static AllocatedPath Null() noexcept {
|
||||||
return AllocatedPath(nullptr);
|
return AllocatedPath(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
operator Path() const {
|
operator Path() const noexcept {
|
||||||
return Path::FromFS(c_str());
|
return Path::FromFS(c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,36 +90,39 @@ public:
|
|||||||
* Join two path components with the path separator.
|
* Join two path components with the path separator.
|
||||||
*/
|
*/
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static AllocatedPath Build(const_pointer_type a, const_pointer_type b) {
|
static AllocatedPath Build(const_pointer_type a,
|
||||||
|
const_pointer_type b) noexcept {
|
||||||
return Build(a, PathTraitsFS::GetLength(a),
|
return Build(a, PathTraitsFS::GetLength(a),
|
||||||
b, PathTraitsFS::GetLength(b));
|
b, PathTraitsFS::GetLength(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static AllocatedPath Build(Path a, const_pointer_type b) {
|
static AllocatedPath Build(Path a, const_pointer_type b) noexcept {
|
||||||
return Build(a.c_str(), b);
|
return Build(a.c_str(), b);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static AllocatedPath Build(Path a, Path b) {
|
static AllocatedPath Build(Path a, Path b) noexcept {
|
||||||
return Build(a, b.c_str());
|
return Build(a, b.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static AllocatedPath Build(const_pointer_type a, const AllocatedPath &b) {
|
static AllocatedPath Build(const_pointer_type a,
|
||||||
|
const AllocatedPath &b) noexcept {
|
||||||
return Build(a, PathTraitsFS::GetLength(a),
|
return Build(a, PathTraitsFS::GetLength(a),
|
||||||
b.value.c_str(), b.value.size());
|
b.value.c_str(), b.value.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static AllocatedPath Build(const AllocatedPath &a, const_pointer_type b) {
|
static AllocatedPath Build(const AllocatedPath &a,
|
||||||
|
const_pointer_type b) noexcept {
|
||||||
return Build(a.value.c_str(), a.value.size(),
|
return Build(a.value.c_str(), a.value.size(),
|
||||||
b, PathTraitsFS::GetLength(b));
|
b, PathTraitsFS::GetLength(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static AllocatedPath Build(const AllocatedPath &a,
|
static AllocatedPath Build(const AllocatedPath &a,
|
||||||
const AllocatedPath &b) {
|
const AllocatedPath &b) noexcept {
|
||||||
return Build(a.value.c_str(), a.value.size(),
|
return Build(a.value.c_str(), a.value.size(),
|
||||||
b.value.c_str(), b.value.size());
|
b.value.c_str(), b.value.size());
|
||||||
}
|
}
|
||||||
@@ -129,13 +132,13 @@ public:
|
|||||||
* character set to a #Path instance.
|
* character set to a #Path instance.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static AllocatedPath FromFS(const_pointer_type fs) {
|
static AllocatedPath FromFS(const_pointer_type fs) noexcept {
|
||||||
return AllocatedPath(fs);
|
return AllocatedPath(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static AllocatedPath FromFS(const_pointer_type _begin,
|
static AllocatedPath FromFS(const_pointer_type _begin,
|
||||||
const_pointer_type _end) {
|
const_pointer_type _end) noexcept {
|
||||||
return AllocatedPath(_begin, _end);
|
return AllocatedPath(_begin, _end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +147,7 @@ public:
|
|||||||
* character set to a #Path instance.
|
* character set to a #Path instance.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static AllocatedPath FromFS(string &&fs) {
|
static AllocatedPath FromFS(string &&fs) noexcept {
|
||||||
return AllocatedPath(std::move(fs));
|
return AllocatedPath(std::move(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,12 +179,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator==(const AllocatedPath &other) const {
|
bool operator==(const AllocatedPath &other) const noexcept {
|
||||||
return value == other.value;
|
return value == other.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator!=(const AllocatedPath &other) const {
|
bool operator!=(const AllocatedPath &other) const noexcept {
|
||||||
return value != other.value;
|
return value != other.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +200,7 @@ public:
|
|||||||
* Check if this is a "nulled" instance. A "nulled" instance
|
* Check if this is a "nulled" instance. A "nulled" instance
|
||||||
* must not be used.
|
* must not be used.
|
||||||
*/
|
*/
|
||||||
bool IsNull() const {
|
bool IsNull() const noexcept {
|
||||||
return value.empty();
|
return value.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +209,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @see IsNull()
|
* @see IsNull()
|
||||||
*/
|
*/
|
||||||
void SetNull() {
|
void SetNull() noexcept {
|
||||||
value.clear();
|
value.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +218,7 @@ public:
|
|||||||
* elements (which may not be the number of characters).
|
* elements (which may not be the number of characters).
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
size_t length() const {
|
size_t length() const noexcept {
|
||||||
return value.length();
|
return value.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +228,7 @@ public:
|
|||||||
* instance ends.
|
* instance ends.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const_pointer_type c_str() const {
|
const_pointer_type c_str() const noexcept {
|
||||||
return value.c_str();
|
return value.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +237,7 @@ public:
|
|||||||
* null-terminated.
|
* null-terminated.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const_pointer_type data() const {
|
const_pointer_type data() const noexcept {
|
||||||
return value.data();
|
return value.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,7 +54,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Check(const char *name_fs) const {
|
bool Check(const char *name_fs) const noexcept {
|
||||||
#ifdef HAVE_FNMATCH
|
#ifdef HAVE_FNMATCH
|
||||||
return fnmatch(pattern.c_str(), name_fs, 0) == 0;
|
return fnmatch(pattern.c_str(), name_fs, 0) == 0;
|
||||||
#elif defined(WIN32)
|
#elif defined(WIN32)
|
||||||
|
@@ -92,7 +92,7 @@ public:
|
|||||||
* elements (which may not be the number of characters).
|
* elements (which may not be the number of characters).
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
size_t length() const {
|
size_t length() const noexcept {
|
||||||
assert(!IsNull());
|
assert(!IsNull());
|
||||||
|
|
||||||
return PathTraitsFS::GetLength(c_str());
|
return PathTraitsFS::GetLength(c_str());
|
||||||
@@ -104,7 +104,7 @@ public:
|
|||||||
* instance ends.
|
* instance ends.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const_pointer_type c_str() const {
|
const_pointer_type c_str() const noexcept {
|
||||||
return Base::c_str();
|
return Base::c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ public:
|
|||||||
* null-terminated.
|
* null-terminated.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const_pointer_type data() const {
|
const_pointer_type data() const noexcept {
|
||||||
return c_str();
|
return c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ struct PathTraitsFS {
|
|||||||
|
|
||||||
static constexpr const_pointer_type CURRENT_DIRECTORY = PATH_LITERAL(".");
|
static constexpr const_pointer_type CURRENT_DIRECTORY = PATH_LITERAL(".");
|
||||||
|
|
||||||
static constexpr bool IsSeparator(value_type ch) {
|
static constexpr bool IsSeparator(value_type ch) noexcept {
|
||||||
return
|
return
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
ch == '/' ||
|
ch == '/' ||
|
||||||
@@ -72,7 +72,7 @@ struct PathTraitsFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static const_pointer_type FindLastSeparator(const_pointer_type p) {
|
static const_pointer_type FindLastSeparator(const_pointer_type p) noexcept {
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
assert(p != nullptr);
|
assert(p != nullptr);
|
||||||
@@ -90,13 +90,13 @@ struct PathTraitsFS {
|
|||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static constexpr bool IsDrive(const_pointer_type p) {
|
static constexpr bool IsDrive(const_pointer_type p) noexcept {
|
||||||
return IsAlphaASCII(p[0]) && p[1] == ':';
|
return IsAlphaASCII(p[0]) && p[1] == ':';
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static bool IsAbsolute(const_pointer_type p) {
|
static bool IsAbsolute(const_pointer_type p) noexcept {
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
assert(p != nullptr);
|
assert(p != nullptr);
|
||||||
@@ -110,12 +110,12 @@ struct PathTraitsFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static size_t GetLength(const_pointer_type p) {
|
static size_t GetLength(const_pointer_type p) noexcept {
|
||||||
return StringLength(p);
|
return StringLength(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static const_pointer_type Find(const_pointer_type p, value_type ch) {
|
static const_pointer_type Find(const_pointer_type p, value_type ch) noexcept {
|
||||||
return StringFind(p, ch);
|
return StringFind(p, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ struct PathTraitsUTF8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static const_pointer_type FindLastSeparator(const_pointer_type p) {
|
static const_pointer_type FindLastSeparator(const_pointer_type p) noexcept {
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
assert(p != nullptr);
|
assert(p != nullptr);
|
||||||
@@ -190,13 +190,13 @@ struct PathTraitsUTF8 {
|
|||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static constexpr bool IsDrive(const_pointer_type p) {
|
static constexpr bool IsDrive(const_pointer_type p) noexcept {
|
||||||
return IsAlphaASCII(p[0]) && p[1] == ':';
|
return IsAlphaASCII(p[0]) && p[1] == ':';
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static bool IsAbsolute(const_pointer_type p) {
|
static bool IsAbsolute(const_pointer_type p) noexcept {
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
assert(p != nullptr);
|
assert(p != nullptr);
|
||||||
@@ -210,12 +210,12 @@ struct PathTraitsUTF8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static size_t GetLength(const_pointer_type p) {
|
static size_t GetLength(const_pointer_type p) noexcept {
|
||||||
return StringLength(p);
|
return StringLength(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static const_pointer_type Find(const_pointer_type p, value_type ch) {
|
static const_pointer_type Find(const_pointer_type p, value_type ch) noexcept {
|
||||||
return StringFind(p, ch);
|
return StringFind(p, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +255,7 @@ struct PathTraitsUTF8 {
|
|||||||
const_pointer_type b, size_t b_size) noexcept;
|
const_pointer_type b, size_t b_size) noexcept;
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
static string Build(const_pointer_type a, const_pointer_type b) {
|
static string Build(const_pointer_type a, const_pointer_type b) noexcept {
|
||||||
return Build(a, GetLength(a), b, GetLength(b));
|
return Build(a, GetLength(a), b, GetLength(b));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -67,7 +67,7 @@ BufferedReader::ReadFull(size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
BufferedReader::ReadFromBuffer(WritableBuffer<void> dest)
|
BufferedReader::ReadFromBuffer(WritableBuffer<void> dest) noexcept
|
||||||
{
|
{
|
||||||
auto src = Read();
|
auto src = Read();
|
||||||
size_t nbytes = std::min(src.size, dest.size);
|
size_t nbytes = std::min(src.size, dest.size);
|
||||||
|
@@ -47,7 +47,7 @@ public:
|
|||||||
* Reset the internal state. Should be called after rewinding
|
* Reset the internal state. Should be called after rewinding
|
||||||
* the underlying #Reader.
|
* the underlying #Reader.
|
||||||
*/
|
*/
|
||||||
void Reset() {
|
void Reset() noexcept {
|
||||||
buffer.Clear();
|
buffer.Clear();
|
||||||
eof = false;
|
eof = false;
|
||||||
line_number = 0;
|
line_number = 0;
|
||||||
@@ -56,7 +56,7 @@ public:
|
|||||||
bool Fill(bool need_more);
|
bool Fill(bool need_more);
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
WritableBuffer<void> Read() const {
|
WritableBuffer<void> Read() const noexcept {
|
||||||
return buffer.Read().ToVoid();
|
return buffer.Read().ToVoid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
void *ReadFull(size_t size);
|
void *ReadFull(size_t size);
|
||||||
|
|
||||||
void Consume(size_t n) {
|
void Consume(size_t n) noexcept {
|
||||||
buffer.Consume(n);
|
buffer.Consume(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ public:
|
|||||||
* Read (and consume) data from the input buffer into the
|
* Read (and consume) data from the input buffer into the
|
||||||
* given buffer. Does not attempt to refill the buffer.
|
* given buffer. Does not attempt to refill the buffer.
|
||||||
*/
|
*/
|
||||||
size_t ReadFromBuffer(WritableBuffer<void> dest);
|
size_t ReadFromBuffer(WritableBuffer<void> dest) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read data into the given buffer and consume it from our
|
* Read data into the given buffer and consume it from our
|
||||||
@@ -86,7 +86,7 @@ public:
|
|||||||
|
|
||||||
char *ReadLine();
|
char *ReadLine();
|
||||||
|
|
||||||
unsigned GetLineNumber() const {
|
unsigned GetLineNumber() const noexcept {
|
||||||
return line_number;
|
return line_number;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -52,14 +52,14 @@ AsyncInputStream::~AsyncInputStream()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncInputStream::SetTag(Tag *_tag)
|
AsyncInputStream::SetTag(Tag *_tag) noexcept
|
||||||
{
|
{
|
||||||
delete tag;
|
delete tag;
|
||||||
tag = _tag;
|
tag = _tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncInputStream::Pause()
|
AsyncInputStream::Pause() noexcept
|
||||||
{
|
{
|
||||||
assert(io_thread_inside());
|
assert(io_thread_inside());
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ AsyncInputStream::Seek(offset_type new_offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncInputStream::SeekDone()
|
AsyncInputStream::SeekDone() noexcept
|
||||||
{
|
{
|
||||||
assert(io_thread_inside());
|
assert(io_thread_inside());
|
||||||
assert(IsSeekPending());
|
assert(IsSeekPending());
|
||||||
@@ -201,7 +201,7 @@ AsyncInputStream::Read(void *ptr, size_t read_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncInputStream::CommitWriteBuffer(size_t nbytes)
|
AsyncInputStream::CommitWriteBuffer(size_t nbytes) noexcept
|
||||||
{
|
{
|
||||||
buffer.Append(nbytes);
|
buffer.Append(nbytes);
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ AsyncInputStream::CommitWriteBuffer(size_t nbytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncInputStream::AppendToBuffer(const void *data, size_t append_size)
|
AsyncInputStream::AppendToBuffer(const void *data, size_t append_size) noexcept
|
||||||
{
|
{
|
||||||
auto w = buffer.Write();
|
auto w = buffer.Write();
|
||||||
assert(!w.IsEmpty());
|
assert(!w.IsEmpty());
|
||||||
@@ -238,7 +238,7 @@ AsyncInputStream::AppendToBuffer(const void *data, size_t append_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncInputStream::DeferredResume()
|
AsyncInputStream::DeferredResume() noexcept
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ AsyncInputStream::DeferredResume()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncInputStream::DeferredSeek()
|
AsyncInputStream::DeferredSeek() noexcept
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
if (seek_state != SeekState::SCHEDULED)
|
if (seek_state != SeekState::SCHEDULED)
|
||||||
|
@@ -92,15 +92,15 @@ protected:
|
|||||||
/**
|
/**
|
||||||
* Pass an tag from the I/O thread to the client thread.
|
* Pass an tag from the I/O thread to the client thread.
|
||||||
*/
|
*/
|
||||||
void SetTag(Tag *_tag);
|
void SetTag(Tag *_tag) noexcept;
|
||||||
|
|
||||||
void ClearTag() {
|
void ClearTag() noexcept {
|
||||||
SetTag(nullptr);
|
SetTag(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pause();
|
void Pause() noexcept;
|
||||||
|
|
||||||
bool IsPaused() const {
|
bool IsPaused() const noexcept {
|
||||||
return paused;
|
return paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,15 +109,15 @@ protected:
|
|||||||
* continue feeding Read() calls from the buffer until it runs
|
* continue feeding Read() calls from the buffer until it runs
|
||||||
* empty.
|
* empty.
|
||||||
*/
|
*/
|
||||||
void SetClosed() {
|
void SetClosed() noexcept {
|
||||||
open = false;
|
open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsBufferEmpty() const {
|
bool IsBufferEmpty() const noexcept {
|
||||||
return buffer.IsEmpty();
|
return buffer.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsBufferFull() const {
|
bool IsBufferFull() const noexcept {
|
||||||
return buffer.IsFull();
|
return buffer.IsFull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,21 +125,21 @@ protected:
|
|||||||
* Determine how many bytes can be added to the buffer.
|
* Determine how many bytes can be added to the buffer.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
size_t GetBufferSpace() const {
|
size_t GetBufferSpace() const noexcept {
|
||||||
return buffer.GetSpace();
|
return buffer.GetSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
CircularBuffer<uint8_t>::Range PrepareWriteBuffer() {
|
CircularBuffer<uint8_t>::Range PrepareWriteBuffer() noexcept {
|
||||||
return buffer.Write();
|
return buffer.Write();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommitWriteBuffer(size_t nbytes);
|
void CommitWriteBuffer(size_t nbytes) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append data to the buffer. The size must fit into the
|
* Append data to the buffer. The size must fit into the
|
||||||
* buffer; see GetBufferSpace().
|
* buffer; see GetBufferSpace().
|
||||||
*/
|
*/
|
||||||
void AppendToBuffer(const void *data, size_t append_size);
|
void AppendToBuffer(const void *data, size_t append_size) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement code here that will resume the stream after it
|
* Implement code here that will resume the stream after it
|
||||||
@@ -154,7 +154,7 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual void DoSeek(offset_type new_offset) = 0;
|
virtual void DoSeek(offset_type new_offset) = 0;
|
||||||
|
|
||||||
bool IsSeekPending() const {
|
bool IsSeekPending() const noexcept {
|
||||||
return seek_state == SeekState::PENDING;
|
return seek_state == SeekState::PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,14 +162,14 @@ protected:
|
|||||||
* Call this after seeking has finished. It will notify the
|
* Call this after seeking has finished. It will notify the
|
||||||
* client thread.
|
* client thread.
|
||||||
*/
|
*/
|
||||||
void SeekDone();
|
void SeekDone() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Resume();
|
void Resume();
|
||||||
|
|
||||||
/* for DeferredCall */
|
/* for DeferredCall */
|
||||||
void DeferredResume();
|
void DeferredResume() noexcept;
|
||||||
void DeferredSeek();
|
void DeferredSeek() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -184,20 +184,20 @@ public:
|
|||||||
void LockWaitReady();
|
void LockWaitReady();
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasMimeType() const {
|
bool HasMimeType() const noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
|
|
||||||
return !mime.empty();
|
return !mime.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetMimeType() const {
|
const char *GetMimeType() const noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
|
|
||||||
return mime.empty() ? nullptr : mime.c_str();
|
return mime.empty() ? nullptr : mime.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearMimeType() {
|
void ClearMimeType() noexcept {
|
||||||
mime.clear();
|
mime.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,35 +215,35 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool KnownSize() const {
|
bool KnownSize() const noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
|
|
||||||
return size != UNKNOWN_SIZE;
|
return size != UNKNOWN_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
offset_type GetSize() const {
|
offset_type GetSize() const noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
assert(KnownSize());
|
assert(KnownSize());
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddOffset(offset_type delta) {
|
void AddOffset(offset_type delta) noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
|
|
||||||
offset += delta;
|
offset += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
offset_type GetOffset() const {
|
offset_type GetOffset() const noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
offset_type GetRest() const {
|
offset_type GetRest() const noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
assert(KnownSize());
|
assert(KnownSize());
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsSeekable() const {
|
bool IsSeekable() const noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
|
|
||||||
return seekable;
|
return seekable;
|
||||||
|
@@ -270,7 +270,10 @@ CdioParanoiaInputStream::Seek(offset_type new_offset)
|
|||||||
lsn_relofs = new_offset / CDIO_CD_FRAMESIZE_RAW;
|
lsn_relofs = new_offset / CDIO_CD_FRAMESIZE_RAW;
|
||||||
offset = new_offset;
|
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
|
size_t
|
||||||
@@ -292,6 +295,8 @@ CdioParanoiaInputStream::Read(void *ptr, size_t length)
|
|||||||
|
|
||||||
//current sector was changed ?
|
//current sector was changed ?
|
||||||
if (lsn_relofs != buffer_lsn) {
|
if (lsn_relofs != buffer_lsn) {
|
||||||
|
const ScopeUnlock unlock(mutex);
|
||||||
|
|
||||||
rbuf = cdio_paranoia_read(para, nullptr);
|
rbuf = cdio_paranoia_read(para, nullptr);
|
||||||
|
|
||||||
s_err = cdda_errors(drv);
|
s_err = cdda_errors(drv);
|
||||||
|
@@ -64,7 +64,6 @@ static const size_t CURL_RESUME_AT = 384 * 1024;
|
|||||||
struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
|
struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
|
||||||
/* some buffers which were passed to libcurl, which we have
|
/* some buffers which were passed to libcurl, which we have
|
||||||
too free */
|
too free */
|
||||||
char range[32];
|
|
||||||
CurlSlist request_headers;
|
CurlSlist request_headers;
|
||||||
|
|
||||||
CurlRequest *request = nullptr;
|
CurlRequest *request = nullptr;
|
||||||
@@ -86,8 +85,19 @@ struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
|
|||||||
|
|
||||||
static InputStream *Open(const char *url, Mutex &mutex, Cond &cond);
|
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();
|
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
|
* Frees the current "libcurl easy" handle, and everything
|
||||||
* associated with it.
|
* associated with it.
|
||||||
@@ -372,6 +382,11 @@ CurlInputStream::InitEasy()
|
|||||||
|
|
||||||
request_headers.Clear();
|
request_headers.Clear();
|
||||||
request_headers.Append("Icy-Metadata: 1");
|
request_headers.Append("Icy-Metadata: 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CurlInputStream::StartRequest()
|
||||||
|
{
|
||||||
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
|
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
|
||||||
|
|
||||||
request->Start();
|
request->Start();
|
||||||
@@ -398,6 +413,7 @@ CurlInputStream::SeekInternal(offset_type new_offset)
|
|||||||
/* send the "Range" header */
|
/* send the "Range" header */
|
||||||
|
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
|
char range[32];
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
// TODO: what can we use on Windows to format 64 bit?
|
// TODO: what can we use on Windows to format 64 bit?
|
||||||
sprintf(range, "%lu-", (long)offset);
|
sprintf(range, "%lu-", (long)offset);
|
||||||
@@ -406,6 +422,8 @@ CurlInputStream::SeekInternal(offset_type new_offset)
|
|||||||
#endif
|
#endif
|
||||||
request->SetOption(CURLOPT_RANGE, range);
|
request->SetOption(CURLOPT_RANGE, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StartRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -428,6 +446,7 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond)
|
|||||||
try {
|
try {
|
||||||
BlockingCall(io_thread_get(), [c](){
|
BlockingCall(io_thread_get(), [c](){
|
||||||
c->InitEasy();
|
c->InitEasy();
|
||||||
|
c->StartRequest();
|
||||||
});
|
});
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
delete c;
|
delete c;
|
||||||
|
@@ -104,7 +104,13 @@ input_ffmpeg_open(const char *uri,
|
|||||||
size_t
|
size_t
|
||||||
FfmpegInputStream::Read(void *ptr, size_t read_size)
|
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) {
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
throw MakeFfmpegError(result, "avio_read() failed");
|
throw MakeFfmpegError(result, "avio_read() failed");
|
||||||
@@ -126,7 +132,12 @@ FfmpegInputStream::IsEOF() noexcept
|
|||||||
void
|
void
|
||||||
FfmpegInputStream::Seek(offset_type new_offset)
|
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)
|
if (result < 0)
|
||||||
throw MakeFfmpegError(result, "avio_seek() failed");
|
throw MakeFfmpegError(result, "avio_seek() failed");
|
||||||
|
@@ -87,14 +87,24 @@ input_file_open(gcc_unused const char *filename,
|
|||||||
void
|
void
|
||||||
FileInputStream::Seek(offset_type new_offset)
|
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;
|
offset = new_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
FileInputStream::Read(void *ptr, size_t read_size)
|
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;
|
offset += nbytes;
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
@@ -125,9 +125,14 @@ input_smbclient_open(const char *uri,
|
|||||||
size_t
|
size_t
|
||||||
SmbclientInputStream::Read(void *ptr, size_t read_size)
|
SmbclientInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
smbclient_mutex.lock();
|
ssize_t nbytes;
|
||||||
ssize_t nbytes = smbc_read(fd, ptr, read_size);
|
|
||||||
smbclient_mutex.unlock();
|
{
|
||||||
|
const ScopeUnlock unlock(mutex);
|
||||||
|
const std::lock_guard<Mutex> lock(smbclient_mutex);
|
||||||
|
nbytes = smbc_read(fd, ptr, read_size);
|
||||||
|
}
|
||||||
|
|
||||||
if (nbytes < 0)
|
if (nbytes < 0)
|
||||||
throw MakeErrno("smbc_read() failed");
|
throw MakeErrno("smbc_read() failed");
|
||||||
|
|
||||||
@@ -138,9 +143,14 @@ SmbclientInputStream::Read(void *ptr, size_t read_size)
|
|||||||
void
|
void
|
||||||
SmbclientInputStream::Seek(offset_type new_offset)
|
SmbclientInputStream::Seek(offset_type new_offset)
|
||||||
{
|
{
|
||||||
smbclient_mutex.lock();
|
off_t result;
|
||||||
off_t result = smbc_lseek(fd, new_offset, SEEK_SET);
|
|
||||||
smbclient_mutex.unlock();
|
{
|
||||||
|
const ScopeUnlock unlock(mutex);
|
||||||
|
const std::lock_guard<Mutex> lock(smbclient_mutex);
|
||||||
|
result = smbc_lseek(fd, new_offset, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
throw MakeErrno("smbc_lseek() failed");
|
throw MakeErrno("smbc_lseek() failed");
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
static int SocketFunction(CURL *easy,
|
static int SocketFunction(CURL *easy,
|
||||||
curl_socket_t s, int action,
|
curl_socket_t s, int action,
|
||||||
void *userp, void *socketp);
|
void *userp, void *socketp) noexcept;
|
||||||
|
|
||||||
virtual bool OnSocketReady(unsigned flags) override;
|
virtual bool OnSocketReady(unsigned flags) override;
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
static unsigned CurlPollToFlags(int action) {
|
static unsigned CurlPollToFlags(int action) noexcept {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case CURL_POLL_NONE:
|
case CURL_POLL_NONE:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -108,7 +108,7 @@ CurlGlobal::CurlGlobal(EventLoop &_loop)
|
|||||||
int
|
int
|
||||||
CurlSocket::SocketFunction(gcc_unused CURL *easy,
|
CurlSocket::SocketFunction(gcc_unused CURL *easy,
|
||||||
curl_socket_t s, int action,
|
curl_socket_t s, int action,
|
||||||
void *userp, void *socketp) {
|
void *userp, void *socketp) noexcept {
|
||||||
auto &global = *(CurlGlobal *)userp;
|
auto &global = *(CurlGlobal *)userp;
|
||||||
CurlSocket *cs = (CurlSocket *)socketp;
|
CurlSocket *cs = (CurlSocket *)socketp;
|
||||||
|
|
||||||
|
102
src/lib/icu/CaseFold.cxx
Normal file
102
src/lib/icu/CaseFold.cxx
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "CaseFold.hxx"
|
||||||
|
|
||||||
|
#ifdef HAVE_ICU_CASE_FOLD
|
||||||
|
|
||||||
|
#include "util/AllocatedString.hxx"
|
||||||
|
|
||||||
|
#ifdef HAVE_ICU
|
||||||
|
#include "Util.hxx"
|
||||||
|
#include "util/AllocatedArray.hxx"
|
||||||
|
#include "util/ConstBuffer.hxx"
|
||||||
|
|
||||||
|
#include <unicode/ucol.h>
|
||||||
|
#include <unicode/ustring.h>
|
||||||
|
#else
|
||||||
|
#include <algorithm>
|
||||||
|
#include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include "Win32.hxx"
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
AllocatedString<>
|
||||||
|
IcuCaseFold(const char *src) noexcept
|
||||||
|
try {
|
||||||
|
#ifdef HAVE_ICU
|
||||||
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
|
assert(src != nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const auto u = UCharFromUTF8(src);
|
||||||
|
if (u.IsNull())
|
||||||
|
return AllocatedString<>::Duplicate(src);
|
||||||
|
|
||||||
|
AllocatedArray<UChar> folded(u.size() * 2u);
|
||||||
|
|
||||||
|
UErrorCode error_code = U_ZERO_ERROR;
|
||||||
|
size_t folded_length = u_strFoldCase(folded.begin(), folded.size(),
|
||||||
|
u.begin(), u.size(),
|
||||||
|
U_FOLD_CASE_DEFAULT,
|
||||||
|
&error_code);
|
||||||
|
if (folded_length == 0 || error_code != U_ZERO_ERROR)
|
||||||
|
return AllocatedString<>::Duplicate(src);
|
||||||
|
|
||||||
|
folded.SetSize(folded_length);
|
||||||
|
return UCharToUTF8({folded.begin(), folded.size()});
|
||||||
|
|
||||||
|
#elif defined(WIN32)
|
||||||
|
const auto u = MultiByteToWideChar(CP_UTF8, src);
|
||||||
|
|
||||||
|
const int size = LCMapStringEx(LOCALE_NAME_INVARIANT,
|
||||||
|
LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
|
||||||
|
u.c_str(), -1, nullptr, 0,
|
||||||
|
nullptr, nullptr, 0);
|
||||||
|
if (size <= 0)
|
||||||
|
return AllocatedString<>::Duplicate(src);
|
||||||
|
|
||||||
|
std::unique_ptr<wchar_t[]> buffer(new wchar_t[size]);
|
||||||
|
if (LCMapStringEx(LOCALE_NAME_INVARIANT,
|
||||||
|
LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
|
||||||
|
u.c_str(), -1, buffer.get(), size,
|
||||||
|
nullptr, nullptr, 0) <= 0)
|
||||||
|
return AllocatedString<>::Duplicate(src);
|
||||||
|
|
||||||
|
return WideCharToMultiByte(CP_UTF8, buffer.get());
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error not implemented
|
||||||
|
#endif
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return AllocatedString<>::Duplicate(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_ICU_CASE_FOLD */
|
38
src/lib/icu/CaseFold.hxx
Normal file
38
src/lib/icu/CaseFold.hxx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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_ICU_CASE_FOLD_HXX
|
||||||
|
#define MPD_ICU_CASE_FOLD_HXX
|
||||||
|
|
||||||
|
#include "check.h"
|
||||||
|
|
||||||
|
#if defined(HAVE_ICU) || defined(_WIN32)
|
||||||
|
#define HAVE_ICU_CASE_FOLD
|
||||||
|
|
||||||
|
#include "Compiler.h"
|
||||||
|
|
||||||
|
template<typename T> class AllocatedString;
|
||||||
|
|
||||||
|
gcc_nonnull_all
|
||||||
|
AllocatedString<char>
|
||||||
|
IcuCaseFold(const char *src) noexcept;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@@ -23,8 +23,6 @@
|
|||||||
|
|
||||||
#ifdef HAVE_ICU
|
#ifdef HAVE_ICU
|
||||||
#include "Util.hxx"
|
#include "Util.hxx"
|
||||||
#include "util/AllocatedArray.hxx"
|
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
|
||||||
#include <unicode/ucol.h>
|
#include <unicode/ucol.h>
|
||||||
@@ -141,70 +139,3 @@ IcuCollate(const char *a, const char *b) noexcept
|
|||||||
return strcoll(a, b);
|
return strcoll(a, b);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocatedString<>
|
|
||||||
IcuCaseFold(const char *src)
|
|
||||||
try {
|
|
||||||
#ifdef HAVE_ICU
|
|
||||||
assert(collator != nullptr);
|
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
|
||||||
assert(src != nullptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const auto u = UCharFromUTF8(src);
|
|
||||||
if (u.IsNull())
|
|
||||||
return AllocatedString<>::Duplicate(src);
|
|
||||||
|
|
||||||
AllocatedArray<UChar> folded(u.size() * 2u);
|
|
||||||
|
|
||||||
UErrorCode error_code = U_ZERO_ERROR;
|
|
||||||
size_t folded_length = u_strFoldCase(folded.begin(), folded.size(),
|
|
||||||
u.begin(), u.size(),
|
|
||||||
U_FOLD_CASE_DEFAULT,
|
|
||||||
&error_code);
|
|
||||||
if (folded_length == 0 || error_code != U_ZERO_ERROR)
|
|
||||||
return AllocatedString<>::Duplicate(src);
|
|
||||||
|
|
||||||
folded.SetSize(folded_length);
|
|
||||||
return UCharToUTF8({folded.begin(), folded.size()});
|
|
||||||
|
|
||||||
#elif defined(WIN32)
|
|
||||||
const auto u = MultiByteToWideChar(CP_UTF8, src);
|
|
||||||
|
|
||||||
const int size = LCMapStringEx(LOCALE_NAME_INVARIANT,
|
|
||||||
LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
|
|
||||||
u.c_str(), -1, nullptr, 0,
|
|
||||||
nullptr, nullptr, 0);
|
|
||||||
if (size <= 0)
|
|
||||||
return AllocatedString<>::Duplicate(src);
|
|
||||||
|
|
||||||
std::unique_ptr<wchar_t[]> buffer(new wchar_t[size]);
|
|
||||||
if (LCMapStringEx(LOCALE_NAME_INVARIANT,
|
|
||||||
LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
|
|
||||||
u.c_str(), -1, buffer.get(), size,
|
|
||||||
nullptr, nullptr, 0) <= 0)
|
|
||||||
return AllocatedString<>::Duplicate(src);
|
|
||||||
|
|
||||||
return WideCharToMultiByte(CP_UTF8, buffer.get());
|
|
||||||
|
|
||||||
#else
|
|
||||||
size_t size = strlen(src) + 1;
|
|
||||||
std::unique_ptr<char[]> buffer(new char[size]);
|
|
||||||
size_t nbytes = strxfrm(buffer.get(), src, size);
|
|
||||||
if (nbytes >= size) {
|
|
||||||
/* buffer too small - reallocate and try again */
|
|
||||||
buffer.reset();
|
|
||||||
size = nbytes + 1;
|
|
||||||
buffer.reset(new char[size]);
|
|
||||||
nbytes = strxfrm(buffer.get(), src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(nbytes < size);
|
|
||||||
assert(buffer[nbytes] == 0);
|
|
||||||
|
|
||||||
return AllocatedString<>::Donate(buffer.release());
|
|
||||||
#endif
|
|
||||||
} catch (const std::runtime_error &) {
|
|
||||||
return AllocatedString<>::Duplicate(src);
|
|
||||||
}
|
|
||||||
|
@@ -23,8 +23,6 @@
|
|||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
template<typename T> class AllocatedString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throws #std::runtime_error on error.
|
* Throws #std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
@@ -38,8 +36,4 @@ gcc_pure gcc_nonnull_all
|
|||||||
int
|
int
|
||||||
IcuCollate(const char *a, const char *b) noexcept;
|
IcuCollate(const char *a, const char *b) noexcept;
|
||||||
|
|
||||||
gcc_nonnull_all
|
|
||||||
AllocatedString<char>
|
|
||||||
IcuCaseFold(const char *src);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
66
src/lib/icu/Compare.cxx
Normal file
66
src/lib/icu/Compare.cxx
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "Compare.hxx"
|
||||||
|
#include "CaseFold.hxx"
|
||||||
|
#include "util/StringAPI.hxx"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_ICU_CASE_FOLD
|
||||||
|
|
||||||
|
IcuCompare::IcuCompare(const char *_needle) noexcept
|
||||||
|
:needle(IcuCaseFold(_needle)) {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
IcuCompare::IcuCompare(const char *_needle) noexcept
|
||||||
|
:needle(AllocatedString<>::Duplicate(_needle)) {}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool
|
||||||
|
IcuCompare::operator==(const char *haystack) const noexcept
|
||||||
|
{
|
||||||
|
#ifdef HAVE_ICU_CASE_FOLD
|
||||||
|
return StringIsEqual(IcuCaseFold(haystack).c_str(), needle.c_str());
|
||||||
|
#else
|
||||||
|
return strcasecmp(haystack, needle.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IcuCompare::IsIn(const char *haystack) const noexcept
|
||||||
|
{
|
||||||
|
#ifdef HAVE_ICU_CASE_FOLD
|
||||||
|
return StringFind(IcuCaseFold(haystack).c_str(),
|
||||||
|
needle.c_str()) != nullptr;
|
||||||
|
#elif defined(HAVE_STRCASESTR)
|
||||||
|
return strcasestr(haystack, needle.c_str()) != nullptr;
|
||||||
|
#else
|
||||||
|
/* poor man's strcasestr() */
|
||||||
|
for (const size_t length = strlen(needle.c_str());
|
||||||
|
*haystack != 0; ++haystack)
|
||||||
|
if (strncasecmp(haystack, needle.c_str(), length) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
55
src/lib/icu/Compare.hxx
Normal file
55
src/lib/icu/Compare.hxx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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_ICU_COMPARE_HXX
|
||||||
|
#define MPD_ICU_COMPARE_HXX
|
||||||
|
|
||||||
|
#include "check.h"
|
||||||
|
#include "Compiler.h"
|
||||||
|
#include "util/AllocatedString.hxx"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can compare one string ("needle") with lots of other
|
||||||
|
* strings ("haystacks") efficiently, ignoring case. With some
|
||||||
|
* configurations, it can prepare a case-folded version of the needle.
|
||||||
|
*/
|
||||||
|
class IcuCompare {
|
||||||
|
AllocatedString<> needle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IcuCompare():needle(nullptr) {}
|
||||||
|
|
||||||
|
explicit IcuCompare(const char *needle) noexcept;
|
||||||
|
|
||||||
|
IcuCompare(IcuCompare &&) = default;
|
||||||
|
IcuCompare &operator=(IcuCompare &&) = default;
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
operator bool() const noexcept {
|
||||||
|
return !needle.IsNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
bool operator==(const char *haystack) const noexcept;
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
bool IsIn(const char *haystack) const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -147,16 +147,16 @@ public:
|
|||||||
~NfsConnection();
|
~NfsConnection();
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetServer() const {
|
const char *GetServer() const noexcept {
|
||||||
return server.c_str();
|
return server.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetExportName() const {
|
const char *GetExportName() const noexcept {
|
||||||
return export_name.c_str();
|
return export_name.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
EventLoop &GetEventLoop() {
|
EventLoop &GetEventLoop() noexcept {
|
||||||
return SocketMonitor::GetEventLoop();
|
return SocketMonitor::GetEventLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,7 +40,7 @@ public:
|
|||||||
return *(UpnpCallback *)cookie;
|
return *(UpnpCallback *)cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int Invoke(Upnp_EventType et, void *evp) = 0;
|
virtual int Invoke(Upnp_EventType et, const void *evp) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -33,7 +33,12 @@ static unsigned upnp_client_ref;
|
|||||||
static UpnpClient_Handle upnp_client_handle;
|
static UpnpClient_Handle upnp_client_handle;
|
||||||
|
|
||||||
static int
|
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)
|
if (cookie == nullptr)
|
||||||
/* this is the cookie passed to UpnpRegisterClient();
|
/* this is the cookie passed to UpnpRegisterClient();
|
||||||
|
69
src/lib/upnp/Compat.hxx
Normal file
69
src/lib/upnp/Compat.hxx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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/upnp.h>
|
||||||
|
|
||||||
|
#if UPNP_VERSION < 10800
|
||||||
|
#include "Compiler.h"
|
||||||
|
|
||||||
|
/* emulate the libupnp 1.8 API with older versions */
|
||||||
|
|
||||||
|
using UpnpDiscovery = Upnp_Discovery;
|
||||||
|
|
||||||
|
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
|
@@ -114,12 +114,12 @@ public:
|
|||||||
std::list<std::string> getSearchCapabilities(UpnpClient_Handle handle) const;
|
std::list<std::string> getSearchCapabilities(UpnpClient_Handle handle) const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
std::string GetURI() const {
|
std::string GetURI() const noexcept {
|
||||||
return "upnp://" + m_deviceId + "/" + m_serviceType;
|
return "upnp://" + m_deviceId + "/" + m_serviceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Retrieve the "friendly name" for this server, useful for display. */
|
/** Retrieve the "friendly name" for this server, useful for display. */
|
||||||
const char *getFriendlyName() const {
|
const char *getFriendlyName() const noexcept {
|
||||||
return m_friendlyName.c_str();
|
return m_friendlyName.c_str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -153,10 +153,10 @@ UPnPDeviceDirectory::Explore(void *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline int
|
inline int
|
||||||
UPnPDeviceDirectory::OnAlive(Upnp_Discovery *disco)
|
UPnPDeviceDirectory::OnAlive(const UpnpDiscovery *disco)
|
||||||
{
|
{
|
||||||
if (isMSDevice(disco->DeviceType) ||
|
if (isMSDevice(UpnpDiscovery_get_DeviceType_cstr(disco)) ||
|
||||||
isCDService(disco->ServiceType)) {
|
isCDService(UpnpDiscovery_get_ServiceType_cstr(disco))) {
|
||||||
DiscoveredTask *tp = new DiscoveredTask(disco);
|
DiscoveredTask *tp = new DiscoveredTask(disco);
|
||||||
if (queue.put(tp))
|
if (queue.put(tp))
|
||||||
return UPNP_E_FINISH;
|
return UPNP_E_FINISH;
|
||||||
@@ -166,12 +166,12 @@ UPnPDeviceDirectory::OnAlive(Upnp_Discovery *disco)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline int
|
inline int
|
||||||
UPnPDeviceDirectory::OnByeBye(Upnp_Discovery *disco)
|
UPnPDeviceDirectory::OnByeBye(const UpnpDiscovery *disco)
|
||||||
{
|
{
|
||||||
if (isMSDevice(disco->DeviceType) ||
|
if (isMSDevice(UpnpDiscovery_get_DeviceType_cstr(disco)) ||
|
||||||
isCDService(disco->ServiceType)) {
|
isCDService(UpnpDiscovery_get_ServiceType_cstr(disco))) {
|
||||||
// Device signals it is going off.
|
// Device signals it is going off.
|
||||||
LockRemove(disco->DeviceId);
|
LockRemove(UpnpDiscovery_get_DeviceID_cstr(disco));
|
||||||
}
|
}
|
||||||
|
|
||||||
return UPNP_E_SUCCESS;
|
return UPNP_E_SUCCESS;
|
||||||
@@ -182,19 +182,19 @@ UPnPDeviceDirectory::OnByeBye(Upnp_Discovery *disco)
|
|||||||
// Example: ContentDirectories appearing and disappearing from the network
|
// Example: ContentDirectories appearing and disappearing from the network
|
||||||
// We queue a task for our worker thread(s)
|
// We queue a task for our worker thread(s)
|
||||||
int
|
int
|
||||||
UPnPDeviceDirectory::Invoke(Upnp_EventType et, void *evp)
|
UPnPDeviceDirectory::Invoke(Upnp_EventType et, const void *evp)
|
||||||
{
|
{
|
||||||
switch (et) {
|
switch (et) {
|
||||||
case UPNP_DISCOVERY_SEARCH_RESULT:
|
case UPNP_DISCOVERY_SEARCH_RESULT:
|
||||||
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
|
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
|
||||||
{
|
{
|
||||||
Upnp_Discovery *disco = (Upnp_Discovery *)evp;
|
auto *disco = (const UpnpDiscovery *)evp;
|
||||||
return OnAlive(disco);
|
return OnAlive(disco);
|
||||||
}
|
}
|
||||||
|
|
||||||
case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
|
case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
|
||||||
{
|
{
|
||||||
Upnp_Discovery *disco = (Upnp_Discovery *)evp;
|
auto *disco = (const UpnpDiscovery *)evp;
|
||||||
return OnByeBye(disco);
|
return OnByeBye(disco);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#ifndef _UPNPPDISC_H_X_INCLUDED_
|
#ifndef _UPNPPDISC_H_X_INCLUDED_
|
||||||
#define _UPNPPDISC_H_X_INCLUDED_
|
#define _UPNPPDISC_H_X_INCLUDED_
|
||||||
|
|
||||||
|
#include "Compat.hxx"
|
||||||
#include "Callback.hxx"
|
#include "Callback.hxx"
|
||||||
#include "Device.hxx"
|
#include "Device.hxx"
|
||||||
#include "WorkQueue.hxx"
|
#include "WorkQueue.hxx"
|
||||||
@@ -34,6 +35,10 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#if UPNP_VERSION < 10800
|
||||||
|
#define UpnpDiscovery Upnp_Discovery
|
||||||
|
#endif
|
||||||
|
|
||||||
class ContentDirectoryService;
|
class ContentDirectoryService;
|
||||||
|
|
||||||
class UPnPDiscoveryListener {
|
class UPnPDiscoveryListener {
|
||||||
@@ -59,10 +64,10 @@ class UPnPDeviceDirectory final : UpnpCallback {
|
|||||||
std::string device_id;
|
std::string device_id;
|
||||||
std::chrono::steady_clock::duration expires;
|
std::chrono::steady_clock::duration expires;
|
||||||
|
|
||||||
DiscoveredTask(const Upnp_Discovery *disco)
|
DiscoveredTask(const UpnpDiscovery *disco)
|
||||||
:url(disco->Location),
|
:url(UpnpDiscovery_get_Location_cstr(disco)),
|
||||||
device_id(disco->DeviceId),
|
device_id(UpnpDiscovery_get_DeviceID_cstr(disco)),
|
||||||
expires(std::chrono::seconds(disco->Expires)) {}
|
expires(std::chrono::seconds(UpnpDiscovery_get_Expires(disco))) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -153,11 +158,11 @@ private:
|
|||||||
static void *Explore(void *);
|
static void *Explore(void *);
|
||||||
void Explore();
|
void Explore();
|
||||||
|
|
||||||
int OnAlive(Upnp_Discovery *disco);
|
int OnAlive(const UpnpDiscovery *disco);
|
||||||
int OnByeBye(Upnp_Discovery *disco);
|
int OnByeBye(const UpnpDiscovery *disco);
|
||||||
|
|
||||||
/* virtual methods from class UpnpCallback */
|
/* virtual methods from class UpnpCallback */
|
||||||
virtual int Invoke(Upnp_EventType et, void *evp) override;
|
virtual int Invoke(Upnp_EventType et, const void *evp) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -84,7 +84,6 @@ public:
|
|||||||
* @return the current volume (0..100 including) or -1 if
|
* @return the current volume (0..100 including) or -1 if
|
||||||
* unavailable
|
* unavailable
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
|
||||||
virtual int GetVolume() = 0;
|
virtual int GetVolume() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -32,6 +32,7 @@ extern const MixerPlugin software_mixer_plugin;
|
|||||||
extern const MixerPlugin alsa_mixer_plugin;
|
extern const MixerPlugin alsa_mixer_plugin;
|
||||||
extern const MixerPlugin haiku_mixer_plugin;
|
extern const MixerPlugin haiku_mixer_plugin;
|
||||||
extern const MixerPlugin oss_mixer_plugin;
|
extern const MixerPlugin oss_mixer_plugin;
|
||||||
|
extern const MixerPlugin osx_mixer_plugin;
|
||||||
extern const MixerPlugin roar_mixer_plugin;
|
extern const MixerPlugin roar_mixer_plugin;
|
||||||
extern const MixerPlugin pulse_mixer_plugin;
|
extern const MixerPlugin pulse_mixer_plugin;
|
||||||
extern const MixerPlugin winmm_mixer_plugin;
|
extern const MixerPlugin winmm_mixer_plugin;
|
||||||
|
69
src/mixer/plugins/OSXMixerPlugin.cxx
Normal file
69
src/mixer/plugins/OSXMixerPlugin.cxx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "mixer/MixerInternal.hxx"
|
||||||
|
#include "output/plugins/OSXOutputPlugin.hxx"
|
||||||
|
|
||||||
|
class OSXMixer final : public Mixer {
|
||||||
|
OSXOutput &output;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OSXMixer(OSXOutput &_output, MixerListener &_listener)
|
||||||
|
:Mixer(osx_mixer_plugin, _listener),
|
||||||
|
output(_output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual methods from class Mixer */
|
||||||
|
void Open() override {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close() override {
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetVolume() override;
|
||||||
|
void SetVolume(unsigned volume) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
OSXMixer::GetVolume()
|
||||||
|
{
|
||||||
|
return osx_output_get_volume(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
OSXMixer::SetVolume(unsigned new_volume)
|
||||||
|
{
|
||||||
|
osx_output_set_volume(output, new_volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Mixer *
|
||||||
|
osx_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
|
||||||
|
MixerListener &listener,
|
||||||
|
gcc_unused const ConfigBlock &block)
|
||||||
|
{
|
||||||
|
OSXOutput &osxo = (OSXOutput &)ao;
|
||||||
|
return new OSXMixer(osxo, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MixerPlugin osx_mixer_plugin = {
|
||||||
|
osx_mixer_init,
|
||||||
|
true,
|
||||||
|
};
|
@@ -48,12 +48,12 @@ class SmbclientNeighborExplorer final : public NeighborExplorer {
|
|||||||
Server(const Server &) = delete;
|
Server(const Server &) = delete;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator==(const Server &other) const {
|
bool operator==(const Server &other) const noexcept {
|
||||||
return name == other.name;
|
return name == other.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
NeighborInfo Export() const {
|
NeighborInfo Export() const noexcept {
|
||||||
return { "smb://" + name + "/", comment };
|
return { "smb://" + name + "/", comment };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -43,12 +43,12 @@ class UpnpNeighborExplorer final
|
|||||||
Server(const Server &) = delete;
|
Server(const Server &) = delete;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator==(const Server &other) const {
|
bool operator==(const Server &other) const noexcept {
|
||||||
return name == other.name;
|
return name == other.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
NeighborInfo Export() const {
|
NeighborInfo Export() const noexcept {
|
||||||
return { "smb://" + name + "/", comment };
|
return { "smb://" + name + "/", comment };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -76,47 +76,47 @@ public:
|
|||||||
|
|
||||||
AllocatedSocketAddress &operator=(const AllocatedSocketAddress &) = delete;
|
AllocatedSocketAddress &operator=(const AllocatedSocketAddress &) = delete;
|
||||||
|
|
||||||
AllocatedSocketAddress &operator=(AllocatedSocketAddress &&src) {
|
AllocatedSocketAddress &operator=(AllocatedSocketAddress &&src) noexcept {
|
||||||
std::swap(address, src.address);
|
std::swap(address, src.address);
|
||||||
std::swap(size, src.size);
|
std::swap(size, src.size);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator==(SocketAddress other) const {
|
bool operator==(SocketAddress other) const noexcept {
|
||||||
return (SocketAddress)*this == other;
|
return (SocketAddress)*this == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(SocketAddress &other) const {
|
bool operator!=(SocketAddress &other) const noexcept {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
static AllocatedSocketAddress Null() {
|
static AllocatedSocketAddress Null() noexcept {
|
||||||
return AllocatedSocketAddress(nullptr, 0);
|
return AllocatedSocketAddress(nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsNull() const {
|
bool IsNull() const noexcept {
|
||||||
return address == nullptr;
|
return address == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type GetSize() const {
|
size_type GetSize() const noexcept {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct sockaddr *GetAddress() const {
|
const struct sockaddr *GetAddress() const noexcept {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator SocketAddress() const {
|
operator SocketAddress() const noexcept {
|
||||||
return SocketAddress(address, size);
|
return SocketAddress(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
operator const struct sockaddr *() const {
|
operator const struct sockaddr *() const noexcept {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetFamily() const {
|
int GetFamily() const noexcept {
|
||||||
return address->sa_family;
|
return address->sa_family;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,11 +124,11 @@ public:
|
|||||||
* Does the object have a well-defined address? Check !IsNull()
|
* Does the object have a well-defined address? Check !IsNull()
|
||||||
* before calling this method.
|
* before calling this method.
|
||||||
*/
|
*/
|
||||||
bool IsDefined() const {
|
bool IsDefined() const noexcept {
|
||||||
return GetFamily() != AF_UNSPEC;
|
return GetFamily() != AF_UNSPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear() {
|
void Clear() noexcept {
|
||||||
free(address);
|
free(address);
|
||||||
address = nullptr;
|
address = nullptr;
|
||||||
size = 0;
|
size = 0;
|
||||||
|
@@ -51,52 +51,52 @@ public:
|
|||||||
|
|
||||||
StaticSocketAddress &operator=(SocketAddress other) noexcept;
|
StaticSocketAddress &operator=(SocketAddress other) noexcept;
|
||||||
|
|
||||||
operator SocketAddress() const {
|
operator SocketAddress() const noexcept {
|
||||||
return SocketAddress(reinterpret_cast<const struct sockaddr *>(&address),
|
return SocketAddress(reinterpret_cast<const struct sockaddr *>(&address),
|
||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr *GetAddress() {
|
struct sockaddr *GetAddress() noexcept {
|
||||||
return reinterpret_cast<struct sockaddr *>(&address);
|
return reinterpret_cast<struct sockaddr *>(&address);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct sockaddr *GetAddress() const {
|
const struct sockaddr *GetAddress() const noexcept {
|
||||||
return reinterpret_cast<const struct sockaddr *>(&address);
|
return reinterpret_cast<const struct sockaddr *>(&address);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_type GetCapacity() const {
|
constexpr size_type GetCapacity() const noexcept {
|
||||||
return sizeof(address);
|
return sizeof(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type GetSize() const {
|
size_type GetSize() const noexcept {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSize(size_type _size) {
|
void SetSize(size_type _size) noexcept {
|
||||||
assert(_size > 0);
|
assert(_size > 0);
|
||||||
assert(size_t(_size) <= sizeof(address));
|
assert(size_t(_size) <= sizeof(address));
|
||||||
|
|
||||||
size = _size;
|
size = _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetFamily() const {
|
int GetFamily() const noexcept {
|
||||||
return address.ss_family;
|
return address.ss_family;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsDefined() const {
|
bool IsDefined() const noexcept {
|
||||||
return GetFamily() != AF_UNSPEC;
|
return GetFamily() != AF_UNSPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear() {
|
void Clear() noexcept {
|
||||||
address.ss_family = AF_UNSPEC;
|
address.ss_family = AF_UNSPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator==(SocketAddress other) const {
|
bool operator==(SocketAddress other) const noexcept {
|
||||||
return (SocketAddress)*this == other;
|
return (SocketAddress)*this == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(SocketAddress &other) const {
|
bool operator!=(SocketAddress &other) const noexcept {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -85,7 +85,7 @@ public:
|
|||||||
* those which are disabled right now.
|
* those which are disabled right now.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
unsigned Size() const {
|
unsigned Size() const noexcept {
|
||||||
return outputs.size();
|
return outputs.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ public:
|
|||||||
* finished yet.
|
* finished yet.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
SignedSongTime GetElapsedTime() const {
|
SignedSongTime GetElapsedTime() const noexcept {
|
||||||
return elapsed_time;
|
return elapsed_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -271,16 +271,15 @@ try {
|
|||||||
inline bool
|
inline bool
|
||||||
AudioOutput::PlayChunk()
|
AudioOutput::PlayChunk()
|
||||||
{
|
{
|
||||||
if (tags) {
|
// ensure pending tags are flushed in all cases
|
||||||
const auto *tag = source.ReadTag();
|
const auto *tag = source.ReadTag();
|
||||||
if (tag != nullptr) {
|
if (tags && tag != nullptr) {
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
try {
|
try {
|
||||||
ao_plugin_send_tag(this, *tag);
|
ao_plugin_send_tag(this, *tag);
|
||||||
} catch (const std::runtime_error &e) {
|
} catch (const std::runtime_error &e) {
|
||||||
FormatError(e, "Failed to send tag to \"%s\" [%s]",
|
FormatError(e, "Failed to send tag to \"%s\" [%s]",
|
||||||
name, plugin.name);
|
name, plugin.name);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -132,7 +132,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetDevice() {
|
const char *GetDevice() const noexcept {
|
||||||
return device.empty() ? default_device : device.c_str();
|
return device.empty() ? default_device : device.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -79,7 +79,7 @@ public:
|
|||||||
size_t Play(const void *chunk, size_t size);
|
size_t Play(const void *chunk, size_t size);
|
||||||
void Cancel();
|
void Cancel();
|
||||||
|
|
||||||
std::chrono::steady_clock::duration Delay();
|
std::chrono::steady_clock::duration Delay() noexcept;
|
||||||
|
|
||||||
void FillBuffer(void* _buffer, size_t size,
|
void FillBuffer(void* _buffer, size_t size,
|
||||||
gcc_unused const media_raw_audio_format& _format);
|
gcc_unused const media_raw_audio_format& _format);
|
||||||
@@ -309,7 +309,7 @@ HaikuOutput::Play(const void *chunk, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline std::chrono::steady_clock::duration
|
inline std::chrono::steady_clock::duration
|
||||||
HaikuOutput::Delay()
|
HaikuOutput::Delay() noexcept
|
||||||
{
|
{
|
||||||
unsigned delay = buffer_filled ? 0 : buffer_delay;
|
unsigned delay = buffer_filled ? 0 : buffer_delay;
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "OSXOutputPlugin.hxx"
|
#include "OSXOutputPlugin.hxx"
|
||||||
#include "../OutputAPI.hxx"
|
#include "../OutputAPI.hxx"
|
||||||
|
#include "mixer/MixerList.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
@@ -53,6 +54,9 @@ struct OSXOutput {
|
|||||||
boost::lockfree::spsc_queue<uint8_t> *ring_buffer;
|
boost::lockfree::spsc_queue<uint8_t> *ring_buffer;
|
||||||
|
|
||||||
OSXOutput(const ConfigBlock &block);
|
OSXOutput(const ConfigBlock &block);
|
||||||
|
|
||||||
|
int GetVolume();
|
||||||
|
void SetVolume(unsigned new_volume);
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Domain osx_output_domain("osx_output");
|
static constexpr Domain osx_output_domain("osx_output");
|
||||||
@@ -103,6 +107,44 @@ OSXOutput::OSXOutput(const ConfigBlock &block)
|
|||||||
sync_sample_rate = block.GetBlockValue("sync_sample_rate", false);
|
sync_sample_rate = block.GetBlockValue("sync_sample_rate", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
OSXOutput::GetVolume()
|
||||||
|
{
|
||||||
|
AudioUnitParameterValue dvolume;
|
||||||
|
char errormsg[1024];
|
||||||
|
|
||||||
|
OSStatus status = AudioUnitGetParameter(au, kHALOutputParam_Volume,
|
||||||
|
kAudioUnitScope_Global, 0, &dvolume);
|
||||||
|
if (status != noErr) {
|
||||||
|
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
|
||||||
|
throw FormatRuntimeError("unable to get volume: %s", errormsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see the explanation in SetVolume, below */
|
||||||
|
return static_cast<int>(dvolume * dvolume * 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
OSXOutput::SetVolume(unsigned new_volume) {
|
||||||
|
char errormsg[1024];
|
||||||
|
|
||||||
|
/* The scaling below makes shifts in volume greater at the lower end
|
||||||
|
* of the scale. This mimics the "feel" of physical volume levers. This is
|
||||||
|
* generally what users of audio software expect.
|
||||||
|
*/
|
||||||
|
|
||||||
|
AudioUnitParameterValue scaled_volume =
|
||||||
|
sqrt(static_cast<AudioUnitParameterValue>(new_volume) / 100.0);
|
||||||
|
|
||||||
|
OSStatus status = AudioUnitSetParameter(au, kHALOutputParam_Volume,
|
||||||
|
kAudioUnitScope_Global, 0, scaled_volume, 0);
|
||||||
|
if (status != noErr) {
|
||||||
|
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
|
||||||
|
throw FormatRuntimeError( "unable to set new volume %u: %s",
|
||||||
|
new_volume, errormsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static AudioOutput *
|
static AudioOutput *
|
||||||
osx_output_init(const ConfigBlock &block)
|
osx_output_init(const ConfigBlock &block)
|
||||||
{
|
{
|
||||||
@@ -670,7 +712,7 @@ osx_output_play(AudioOutput *ao, const void *chunk, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::chrono::steady_clock::duration
|
static std::chrono::steady_clock::duration
|
||||||
osx_output_delay(AudioOutput *ao)
|
osx_output_delay(AudioOutput *ao) noexcept
|
||||||
{
|
{
|
||||||
OSXOutput *od = (OSXOutput *)ao;
|
OSXOutput *od = (OSXOutput *)ao;
|
||||||
return od->ring_buffer->write_available()
|
return od->ring_buffer->write_available()
|
||||||
@@ -678,6 +720,18 @@ osx_output_delay(AudioOutput *ao)
|
|||||||
: std::chrono::milliseconds(25);
|
: std::chrono::milliseconds(25);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
osx_output_get_volume(OSXOutput &output)
|
||||||
|
{
|
||||||
|
return output.GetVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
osx_output_set_volume(OSXOutput &output, unsigned new_volume)
|
||||||
|
{
|
||||||
|
return output.SetVolume(new_volume);
|
||||||
|
}
|
||||||
|
|
||||||
const struct AudioOutputPlugin osx_output_plugin = {
|
const struct AudioOutputPlugin osx_output_plugin = {
|
||||||
"osx",
|
"osx",
|
||||||
osx_output_test_default_device,
|
osx_output_test_default_device,
|
||||||
@@ -693,5 +747,6 @@ const struct AudioOutputPlugin osx_output_plugin = {
|
|||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
|
||||||
|
&osx_mixer_plugin,
|
||||||
};
|
};
|
||||||
|
@@ -20,6 +20,14 @@
|
|||||||
#ifndef MPD_OSX_OUTPUT_PLUGIN_HXX
|
#ifndef MPD_OSX_OUTPUT_PLUGIN_HXX
|
||||||
#define MPD_OSX_OUTPUT_PLUGIN_HXX
|
#define MPD_OSX_OUTPUT_PLUGIN_HXX
|
||||||
|
|
||||||
|
struct OSXOutput;
|
||||||
|
|
||||||
extern const struct AudioOutputPlugin osx_output_plugin;
|
extern const struct AudioOutputPlugin osx_output_plugin;
|
||||||
|
|
||||||
|
int
|
||||||
|
osx_output_get_volume(OSXOutput &output);
|
||||||
|
|
||||||
|
void
|
||||||
|
osx_output_set_volume(OSXOutput &output, unsigned new_volume);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -73,19 +73,19 @@ class OpenALOutput {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
gcc_pure
|
gcc_pure
|
||||||
ALint GetSourceI(ALenum param) const {
|
ALint GetSourceI(ALenum param) const noexcept {
|
||||||
ALint value;
|
ALint value;
|
||||||
alGetSourcei(source, param, &value);
|
alGetSourcei(source, param, &value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasProcessed() const {
|
bool HasProcessed() const noexcept {
|
||||||
return GetSourceI(AL_BUFFERS_PROCESSED) > 0;
|
return GetSourceI(AL_BUFFERS_PROCESSED) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsPlaying() const {
|
bool IsPlaying() const noexcept {
|
||||||
return GetSourceI(AL_SOURCE_STATE) == AL_PLAYING;
|
return GetSourceI(AL_SOURCE_STATE) == AL_PLAYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -100,7 +100,7 @@ public:
|
|||||||
void Open(AudioFormat &audio_format);
|
void Open(AudioFormat &audio_format);
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
std::chrono::steady_clock::duration Delay();
|
std::chrono::steady_clock::duration Delay() noexcept;
|
||||||
size_t Play(const void *chunk, size_t size);
|
size_t Play(const void *chunk, size_t size);
|
||||||
void Cancel();
|
void Cancel();
|
||||||
bool Pause();
|
bool Pause();
|
||||||
@@ -740,7 +740,7 @@ PulseOutput::StreamPause(bool pause)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline std::chrono::steady_clock::duration
|
inline std::chrono::steady_clock::duration
|
||||||
PulseOutput::Delay()
|
PulseOutput::Delay() noexcept
|
||||||
{
|
{
|
||||||
Pulse::LockGuard lock(mainloop);
|
Pulse::LockGuard lock(mainloop);
|
||||||
|
|
||||||
|
@@ -97,7 +97,7 @@ class RecorderOutput {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasDynamicPath() const {
|
bool HasDynamicPath() const noexcept {
|
||||||
return !format_path.empty();
|
return !format_path.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@ class SndioOutput {
|
|||||||
AudioOutput base;
|
AudioOutput base;
|
||||||
const char *const device;
|
const char *const device;
|
||||||
const unsigned buffer_time; /* in ms */
|
const unsigned buffer_time; /* in ms */
|
||||||
struct sio_hdl *sio_hdl;
|
struct sio_hdl *hdl;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SndioOutput(const ConfigBlock &block);
|
SndioOutput(const ConfigBlock &block);
|
||||||
@@ -80,16 +80,14 @@ SndioOutput::Create(const ConfigBlock &block)
|
|||||||
static bool
|
static bool
|
||||||
sndio_test_default_device()
|
sndio_test_default_device()
|
||||||
{
|
{
|
||||||
struct sio_hdl *sio_hdl;
|
auto *hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0);
|
||||||
|
if (!hdl) {
|
||||||
sio_hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0);
|
|
||||||
if (!sio_hdl) {
|
|
||||||
FormatError(sndio_output_domain,
|
FormatError(sndio_output_domain,
|
||||||
"Error opening default sndio device");
|
"Error opening default sndio device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sio_close(sio_hdl);
|
sio_close(hdl);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,8 +97,8 @@ SndioOutput::Open(AudioFormat &audio_format)
|
|||||||
struct sio_par par;
|
struct sio_par par;
|
||||||
unsigned bits, rate, chans;
|
unsigned bits, rate, chans;
|
||||||
|
|
||||||
sio_hdl = sio_open(device, SIO_PLAY, 0);
|
hdl = sio_open(device, SIO_PLAY, 0);
|
||||||
if (!sio_hdl)
|
if (!hdl)
|
||||||
throw std::runtime_error("Failed to open default sndio device");
|
throw std::runtime_error("Failed to open default sndio device");
|
||||||
|
|
||||||
switch (audio_format.format) {
|
switch (audio_format.format) {
|
||||||
@@ -130,9 +128,9 @@ SndioOutput::Open(AudioFormat &audio_format)
|
|||||||
par.le = SIO_LE_NATIVE;
|
par.le = SIO_LE_NATIVE;
|
||||||
par.appbufsz = rate * buffer_time / 1000;
|
par.appbufsz = rate * buffer_time / 1000;
|
||||||
|
|
||||||
if (!sio_setpar(sio_hdl, &par) ||
|
if (!sio_setpar(hdl, &par) ||
|
||||||
!sio_getpar(sio_hdl, &par)) {
|
!sio_getpar(hdl, &par)) {
|
||||||
sio_close(sio_hdl);
|
sio_close(hdl);
|
||||||
throw std::runtime_error("Failed to set/get audio params");
|
throw std::runtime_error("Failed to set/get audio params");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,12 +140,12 @@ SndioOutput::Open(AudioFormat &audio_format)
|
|||||||
par.pchan != chans ||
|
par.pchan != chans ||
|
||||||
par.sig != 1 ||
|
par.sig != 1 ||
|
||||||
par.le != SIO_LE_NATIVE) {
|
par.le != SIO_LE_NATIVE) {
|
||||||
sio_close(sio_hdl);
|
sio_close(hdl);
|
||||||
throw std::runtime_error("Requested audio params cannot be satisfied");
|
throw std::runtime_error("Requested audio params cannot be satisfied");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sio_start(sio_hdl)) {
|
if (!sio_start(hdl)) {
|
||||||
sio_close(sio_hdl);
|
sio_close(hdl);
|
||||||
throw std::runtime_error("Failed to start audio device");
|
throw std::runtime_error("Failed to start audio device");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +153,7 @@ SndioOutput::Open(AudioFormat &audio_format)
|
|||||||
void
|
void
|
||||||
SndioOutput::Close()
|
SndioOutput::Close()
|
||||||
{
|
{
|
||||||
sio_close(sio_hdl);
|
sio_close(hdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
@@ -163,8 +161,8 @@ SndioOutput::Play(const void *chunk, size_t size)
|
|||||||
{
|
{
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
n = sio_write(sio_hdl, chunk, size);
|
n = sio_write(hdl, chunk, size);
|
||||||
if (n == 0 && sio_eof(sio_hdl) != 0)
|
if (n == 0 && sio_eof(hdl) != 0)
|
||||||
throw std::runtime_error("sndio write failed");
|
throw std::runtime_error("sndio write failed");
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@@ -191,7 +191,7 @@ public:
|
|||||||
* Caller must lock the mutex.
|
* Caller must lock the mutex.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasClients() const {
|
bool HasClients() const noexcept {
|
||||||
return !clients.empty();
|
return !clients.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ public:
|
|||||||
* Check whether there is at least one client.
|
* Check whether there is at least one client.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool LockHasClients() const {
|
bool LockHasClients() const noexcept {
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
return HasClients();
|
return HasClients();
|
||||||
}
|
}
|
||||||
|
@@ -468,6 +468,7 @@ HttpdOutput::SendTag(const Tag &tag)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
encoder->SendTag(tag);
|
encoder->SendTag(tag);
|
||||||
|
encoder->Flush();
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
/* ignore */
|
/* ignore */
|
||||||
}
|
}
|
||||||
|
@@ -96,7 +96,7 @@ public:
|
|||||||
void Open(AudioFormat &audio_format);
|
void Open(AudioFormat &audio_format);
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
std::chrono::steady_clock::duration Delay() {
|
std::chrono::steady_clock::duration Delay() noexcept {
|
||||||
return pause && !cancel
|
return pause && !cancel
|
||||||
? std::chrono::milliseconds(100)
|
? std::chrono::milliseconds(100)
|
||||||
: std::chrono::steady_clock::duration::zero();
|
: std::chrono::steady_clock::duration::zero();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user