Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f591193dda | ||
|
|
434869900e | ||
|
|
2aed7378cc | ||
|
|
71cd6e6248 | ||
|
|
c83294916a | ||
|
|
603bbe0afd | ||
|
|
c361e235eb | ||
|
|
8a59493d96 | ||
|
|
7ef86cbf9f | ||
|
|
c9530118a4 | ||
|
|
878d9abeb7 | ||
|
|
2d705efe1c | ||
|
|
aeaef85507 | ||
|
|
ebae25d175 | ||
|
|
5ad1a01d7a | ||
|
|
8f84e1befd | ||
|
|
9975905faf | ||
|
|
233184568c | ||
|
|
59da778009 | ||
|
|
108ce95b7c | ||
|
|
86e9ed5f3a | ||
|
|
fbecb05bf4 | ||
|
|
4983703375 | ||
|
|
3856224df9 | ||
|
|
6d4bedfc56 | ||
|
|
bea821f194 | ||
|
|
4e276256c0 | ||
|
|
d0f9062b56 | ||
|
|
b9cc036703 | ||
|
|
4e9b88559b | ||
|
|
3452682a42 | ||
|
|
9262b24504 | ||
|
|
a5fa43b526 | ||
|
|
8681a3d74c | ||
|
|
f9c4d88b12 | ||
|
|
799032505e | ||
|
|
c8f174ac92 | ||
|
|
047e169f3e | ||
|
|
687327c9e8 | ||
|
|
26dc37bd76 | ||
|
|
c693e4aa64 | ||
|
|
acab731fef | ||
|
|
7e4ba3cb72 | ||
|
|
172c4d9c7d | ||
|
|
bd5f6cbc7b | ||
|
|
6fcd1c734b | ||
|
|
eca097dbfb | ||
|
|
51ffafa011 | ||
|
|
8dca602346 | ||
|
|
0ed24f3a05 | ||
|
|
e25e0030e7 |
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@@ -12,7 +12,7 @@ on:
|
|||||||
- 'win32/**'
|
- 'win32/**'
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- actions
|
- v0.23.x
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'android/**'
|
- 'android/**'
|
||||||
@@ -24,6 +24,7 @@ on:
|
|||||||
- 'win32/**'
|
- 'win32/**'
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- v0.23.x
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-linux:
|
build-linux:
|
||||||
|
|||||||
11
NEWS
11
NEWS
@@ -1,3 +1,14 @@
|
|||||||
|
ver 0.23.6 (2022/03/14)
|
||||||
|
* protocol
|
||||||
|
- support filename "cover.webp" for "albumart" command
|
||||||
|
- support "readcomments" and "readpicture" on CUE tracks
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: fix end-of-file check (update stuck at empty files)
|
||||||
|
- opus: fix "readpicture" on Opus files
|
||||||
|
* output
|
||||||
|
- pipewire: fix crash bug if setting volume before playback starts
|
||||||
|
- wasapi: fix resume after pause
|
||||||
|
|
||||||
ver 0.23.5 (2021/12/01)
|
ver 0.23.5 (2021/12/01)
|
||||||
* protocol
|
* protocol
|
||||||
- support relative offsets for "searchadd"
|
- support relative offsets for "searchadd"
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
|
||||||
|
|
||||||
<application android:allowBackup="true"
|
<application android:allowBackup="true"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
@@ -43,7 +41,6 @@
|
|||||||
<receiver android:name=".Receiver">
|
<receiver android:name=".Receiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="android.intent.action.HEADSET_PLUG" />
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<service android:name=".Main" android:process=":main"/>
|
<service android:name=".Main" android:process=":main"/>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ android_abi = sys.argv[3]
|
|||||||
configure_args = sys.argv[4:]
|
configure_args = sys.argv[4:]
|
||||||
|
|
||||||
if not os.path.isfile(os.path.join(sdk_path, 'tools', 'android')):
|
if not os.path.isfile(os.path.join(sdk_path, 'tools', 'android')):
|
||||||
print("SDK not found in", ndk_path, file=sys.stderr)
|
print("SDK not found in", sdk_path, file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not os.path.isdir(ndk_path):
|
if not os.path.isdir(ndk_path):
|
||||||
|
|||||||
@@ -24,14 +24,13 @@ import android.app.Notification;
|
|||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.bluetooth.BluetoothDevice;
|
|
||||||
import android.bluetooth.BluetoothClass;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
|
import android.media.AudioManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
@@ -200,24 +199,14 @@ public class Main extends Service implements Runnable {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(Intent.ACTION_HEADSET_PLUG);
|
filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
|
||||||
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
|
|
||||||
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
|
|
||||||
registerReceiver(new BroadcastReceiver() {
|
registerReceiver(new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (!mPauseOnHeadphonesDisconnect) {
|
if (!mPauseOnHeadphonesDisconnect)
|
||||||
return;
|
return;
|
||||||
}
|
if (intent.getAction() == AudioManager.ACTION_AUDIO_BECOMING_NOISY)
|
||||||
|
pause();
|
||||||
if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
|
|
||||||
if (intent.hasExtra("state") && intent.getIntExtra("state", 0) == 0)
|
|
||||||
pause();
|
|
||||||
} else {
|
|
||||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
|
||||||
if (device.getBluetoothClass().hasService(BluetoothClass.Service.AUDIO))
|
|
||||||
pause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, filter);
|
}, filter);
|
||||||
|
|
||||||
|
|||||||
@@ -25,16 +25,18 @@ import android.content.Intent;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class Receiver extends BroadcastReceiver {
|
public class Receiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Log.d("Receiver", "onReceive: " + intent);
|
Log.d("Receiver", "onReceive: " + intent);
|
||||||
if (intent.getAction() == "android.intent.action.BOOT_COMPLETED") {
|
if (intent.getAction() == "android.intent.action.BOOT_COMPLETED") {
|
||||||
if (Settings.Preferences.getBoolean(context,
|
if (Settings.Preferences.getBoolean(context,
|
||||||
Settings.Preferences.KEY_RUN_ON_BOOT, false)) {
|
Settings.Preferences.KEY_RUN_ON_BOOT,
|
||||||
final boolean wakelock = Settings.Preferences.getBoolean(context,
|
false)) {
|
||||||
Settings.Preferences.KEY_WAKELOCK, false);
|
final boolean wakelock =
|
||||||
Main.start(context, wakelock);
|
Settings.Preferences.getBoolean(context,
|
||||||
}
|
Settings.Preferences.KEY_WAKELOCK, false);
|
||||||
}
|
Main.start(context, wakelock);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ author = 'Max Kellermann'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.23.5'
|
version = '0.23.6'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
#release = version + '~git'
|
#release = version + '~git'
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
# This setting sets the address for the daemon to listen on. Careful attention
|
# This setting sets the address for the daemon to listen on. Careful attention
|
||||||
# should be paid if this is assigned to anything other than the default, any.
|
# should be paid if this is assigned to anything other than the default, any.
|
||||||
# This setting can deny access to control of the daemon. Not effective if
|
# This setting can deny access to control of the daemon. Not effective if
|
||||||
# systemd socket activiation is in use.
|
# systemd socket activation is in use.
|
||||||
#
|
#
|
||||||
# For network
|
# For network
|
||||||
#bind_to_address "any"
|
#bind_to_address "any"
|
||||||
@@ -185,7 +185,7 @@
|
|||||||
# cache_directory "~/.local/share/mpd/cache"
|
# cache_directory "~/.local/share/mpd/cache"
|
||||||
#}
|
#}
|
||||||
#
|
#
|
||||||
# An example of database config for a sattelite setup
|
# An example of database config for a satellite setup
|
||||||
#
|
#
|
||||||
#music_directory "nfs://fileserver.local/srv/mp3"
|
#music_directory "nfs://fileserver.local/srv/mp3"
|
||||||
#database {
|
#database {
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ Querying :program:`MPD`'s status
|
|||||||
current song in seconds, but with higher resolution.
|
current song in seconds, but with higher resolution.
|
||||||
- ``duration`` [#since_0_20]_: Duration of the current song in seconds.
|
- ``duration`` [#since_0_20]_: Duration of the current song in seconds.
|
||||||
- ``bitrate``: instantaneous bitrate in kbps
|
- ``bitrate``: instantaneous bitrate in kbps
|
||||||
- ``xfade``: ``crossfade`` in seconds
|
- ``xfade``: ``crossfade`` in seconds (see :ref:`crossfading`)
|
||||||
- ``mixrampdb``: ``mixramp`` threshold in dB
|
- ``mixrampdb``: ``mixramp`` threshold in dB
|
||||||
- ``mixrampdelay``: ``mixrampdelay`` in seconds
|
- ``mixrampdelay``: ``mixrampdelay`` in seconds
|
||||||
- ``audio``: The format emitted by the decoder plugin during
|
- ``audio``: The format emitted by the decoder plugin during
|
||||||
@@ -519,17 +519,19 @@ Playback options
|
|||||||
.. _command_crossfade:
|
.. _command_crossfade:
|
||||||
|
|
||||||
:command:`crossfade {SECONDS}`
|
:command:`crossfade {SECONDS}`
|
||||||
Sets crossfading between songs.
|
Sets crossfading between songs. See :ref:`crossfading`.
|
||||||
|
|
||||||
.. _command_mixrampdb:
|
.. _command_mixrampdb:
|
||||||
|
|
||||||
:command:`mixrampdb {deciBels}`
|
:command:`mixrampdb {deciBels}`
|
||||||
Sets the threshold at which songs will be overlapped. Like crossfading but doesn't fade the track volume, just overlaps. The songs need to have MixRamp tags added by an external tool. 0dB is the normalized maximum volume so use negative values, I prefer -17dB. In the absence of mixramp tags crossfading will be used. See http://sourceforge.net/projects/mixramp
|
Sets the threshold at which songs will be overlapped.
|
||||||
|
See :ref:`mixramp`.
|
||||||
|
|
||||||
.. _command_mixrampdelay:
|
.. _command_mixrampdelay:
|
||||||
|
|
||||||
:command:`mixrampdelay {SECONDS}`
|
:command:`mixrampdelay {SECONDS}`
|
||||||
Additional time subtracted from the overlap calculated by mixrampdb. A value of "nan" disables MixRamp overlapping and falls back to crossfading.
|
Additional time subtracted from the overlap calculated by mixrampdb. A value of "nan" disables MixRamp overlapping and falls back to crossfading.
|
||||||
|
See :ref:`mixramp`.
|
||||||
|
|
||||||
.. _command_random:
|
.. _command_random:
|
||||||
|
|
||||||
@@ -771,8 +773,8 @@ Whenever possible, ids should be used.
|
|||||||
.. _command_playlistfind:
|
.. _command_playlistfind:
|
||||||
|
|
||||||
:command:`playlistfind {FILTER}`
|
:command:`playlistfind {FILTER}`
|
||||||
Finds songs in the queue with strict
|
Search the queue for songs matching
|
||||||
matching.
|
``FILTER`` (see :ref:`Filters <filter_syntax>`).
|
||||||
|
|
||||||
.. _command_playlistid:
|
.. _command_playlistid:
|
||||||
|
|
||||||
@@ -792,8 +794,10 @@ Whenever possible, ids should be used.
|
|||||||
.. _command_playlistsearch:
|
.. _command_playlistsearch:
|
||||||
|
|
||||||
:command:`playlistsearch {FILTER}`
|
:command:`playlistsearch {FILTER}`
|
||||||
Searches case-insensitively for partial matches in the
|
Search the queue for songs matching
|
||||||
queue.
|
``FILTER`` (see :ref:`Filters <filter_syntax>`).
|
||||||
|
Parameters have the same meaning as for :ref:`find
|
||||||
|
<command_playlistfind>`, except that search is not case sensitive.
|
||||||
|
|
||||||
.. _command_plchanges:
|
.. _command_plchanges:
|
||||||
|
|
||||||
|
|||||||
54
doc/user.rst
54
doc/user.rst
@@ -622,6 +622,51 @@ enabled by setting ``volume_normalization`` to ``yes``. It supports
|
|||||||
16 bit PCM only.
|
16 bit PCM only.
|
||||||
|
|
||||||
|
|
||||||
|
.. _crossfading:
|
||||||
|
|
||||||
|
Cross-Fading
|
||||||
|
------------
|
||||||
|
|
||||||
|
If ``crossfade`` is set to a positive number, then adjacent songs are
|
||||||
|
cross-faded by this number of seconds. This is a run-time setting
|
||||||
|
:ref:`which can be controlled by clients <command_crossfade>`,
|
||||||
|
e.g. with :program:`mpc`::
|
||||||
|
|
||||||
|
mpc crossfade 10
|
||||||
|
mpc crossfade 0
|
||||||
|
|
||||||
|
Zero means cross-fading is disabled.
|
||||||
|
|
||||||
|
Cross-fading is only possible if both songs have the same audio
|
||||||
|
format. At the cost of quality loss and higher CPU usage, you can
|
||||||
|
make sure this is always given by configuring
|
||||||
|
:ref:`audio_output_format`.
|
||||||
|
|
||||||
|
.. _mixramp:
|
||||||
|
|
||||||
|
MixRamp
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
MixRamp tags describe the loudness levels at start and end of a song
|
||||||
|
and can be used by MPD to find the best time to begin cross-fading.
|
||||||
|
MPD enables MixRamp if:
|
||||||
|
|
||||||
|
- Cross-fade is enabled
|
||||||
|
- :ref:`mixrampdelay <command_mixrampdelay>` is set to a positive
|
||||||
|
value, e.g.::
|
||||||
|
mpc mixrampdelay 1
|
||||||
|
- :ref:`mixrampdb <command_mixrampdb>` is set to a reasonable value,
|
||||||
|
e.g.::
|
||||||
|
mpc mixrampdb -17
|
||||||
|
- both songs have MixRamp tags
|
||||||
|
- both songs have the same audio format (or :ref:`audio_output_format`
|
||||||
|
is configured)
|
||||||
|
|
||||||
|
The `MixRamp <http://sourceforge.net/projects/mixramp>`__ tool can be
|
||||||
|
used to add MixRamp tags to your song files.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Client Connections
|
Client Connections
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@@ -1058,6 +1103,15 @@ See :ref:`tags` for a list of supported tags.
|
|||||||
The :ref:`metadata_to_use <metadata_to_use>` setting can be used to
|
The :ref:`metadata_to_use <metadata_to_use>` setting can be used to
|
||||||
enable or disable certain tags.
|
enable or disable certain tags.
|
||||||
|
|
||||||
|
Note that :program:`MPD` may not necessarily read metadata itself,
|
||||||
|
instead relying on data reported by the decoder that was used to read
|
||||||
|
a file. For example, this is the case for the FFmpeg decoder: both
|
||||||
|
:program:`MPD` and FFmpeg need to support a given metadata format in
|
||||||
|
order for metadata to be picked up correctly.
|
||||||
|
|
||||||
|
Only if a decoder does not have metadata support will :program:`MPD`
|
||||||
|
attempt to parse a song's metadata itself.
|
||||||
|
|
||||||
The queue
|
The queue
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
project(
|
project(
|
||||||
'mpd',
|
'mpd',
|
||||||
['c', 'cpp'],
|
['c', 'cpp'],
|
||||||
version: '0.23.5',
|
version: '0.23.6',
|
||||||
meson_version: '>= 0.56.0',
|
meson_version: '>= 0.56.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ from build.boost import BoostProject
|
|||||||
from build.jack import JackProject
|
from build.jack import JackProject
|
||||||
|
|
||||||
libmpdclient = MesonProject(
|
libmpdclient = MesonProject(
|
||||||
'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.19.tar.xz',
|
'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.20.tar.xz',
|
||||||
'158aad4c2278ab08e76a3f2b0166c99b39fae00ee17231bd225c5a36e977a189',
|
'18793f68e939c3301e34d8fcadea1f7daa24143941263cecadb80126194e277d',
|
||||||
'lib/libmpdclient.a',
|
'lib/libmpdclient.a',
|
||||||
)
|
)
|
||||||
|
|
||||||
libogg = CmakeProject(
|
libogg = CmakeProject(
|
||||||
'http://downloads.xiph.org/releases/ogg/libogg-1.3.4.tar.xz',
|
'http://downloads.xiph.org/releases/ogg/libogg-1.3.5.tar.xz',
|
||||||
'c163bc12bc300c401b6aa35907ac682671ea376f13ae0969a220f7ddf71893fe',
|
'c4d91be36fc8e54deae7575241e03f4211eb102afb3fc0775fbbc1b740016705',
|
||||||
'lib/libogg.a',
|
'lib/libogg.a',
|
||||||
[
|
[
|
||||||
'-DBUILD_SHARED_LIBS=OFF',
|
'-DBUILD_SHARED_LIBS=OFF',
|
||||||
@@ -43,8 +43,8 @@ opus = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
flac = AutotoolsProject(
|
flac = AutotoolsProject(
|
||||||
'http://downloads.xiph.org/releases/flac/flac-1.3.3.tar.xz',
|
'http://downloads.xiph.org/releases/flac/flac-1.3.4.tar.xz',
|
||||||
'213e82bd716c9de6db2f98bcadbc4c24c7e2efe8c75939a1a84e28539c4e1748',
|
'8ff0607e75a322dd7cd6ec48f4f225471404ae2730d0ea945127b1355155e737',
|
||||||
'lib/libFLAC.a',
|
'lib/libFLAC.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -151,8 +151,8 @@ gme = CmakeProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
ffmpeg = FfmpegProject(
|
ffmpeg = FfmpegProject(
|
||||||
'http://ffmpeg.org/releases/ffmpeg-4.4.1.tar.xz',
|
'http://ffmpeg.org/releases/ffmpeg-5.0.tar.xz',
|
||||||
'eadbad9e9ab30b25f5520fbfde99fae4a92a1ae3c0257a8d68569a4651e30e02',
|
'51e919f7d205062c0fd4fae6243a84850391115104ccf1efc451733bc0ac7298',
|
||||||
'lib/libavcodec.a',
|
'lib/libavcodec.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -380,14 +380,14 @@ ffmpeg = FfmpegProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
openssl = OpenSSLProject(
|
openssl = OpenSSLProject(
|
||||||
'https://www.openssl.org/source/openssl-3.0.0.tar.gz',
|
'https://www.openssl.org/source/openssl-3.0.1.tar.gz',
|
||||||
'59eedfcb46c25214c9bd37ed6078297b4df01d012267fe9e9eee31f61bc70536',
|
'c311ad853353bce796edad01a862c50a8a587f62e7e2100ef465ab53ec9b06d1',
|
||||||
'include/openssl/ossl_typ.h',
|
'include/openssl/ossl_typ.h',
|
||||||
)
|
)
|
||||||
|
|
||||||
curl = CmakeProject(
|
curl = CmakeProject(
|
||||||
'https://curl.se/download/curl-7.79.1.tar.xz',
|
'https://curl.se/download/curl-7.82.0.tar.xz',
|
||||||
'0606f74b1182ab732a17c11613cbbaf7084f2e6cca432642d0e3ad7c224c3689',
|
'0aaa12d7bd04b0966254f2703ce80dd5c38dbbd76af0297d3d690cdce58a583c',
|
||||||
'lib/libcurl.a',
|
'lib/libcurl.a',
|
||||||
[
|
[
|
||||||
'-DBUILD_CURL_EXE=OFF',
|
'-DBUILD_CURL_EXE=OFF',
|
||||||
@@ -415,14 +415,14 @@ curl = CmakeProject(
|
|||||||
'-DBUILD_TESTING=OFF',
|
'-DBUILD_TESTING=OFF',
|
||||||
],
|
],
|
||||||
windows_configure_args=[
|
windows_configure_args=[
|
||||||
'-DCMAKE_USE_SCHANNEL=ON',
|
'-DCURL_USE_SCHANNEL=ON',
|
||||||
],
|
],
|
||||||
patches='src/lib/curl/patches',
|
patches='src/lib/curl/patches',
|
||||||
)
|
)
|
||||||
|
|
||||||
libnfs = AutotoolsProject(
|
libnfs = AutotoolsProject(
|
||||||
'https://github.com/sahlberg/libnfs/archive/libnfs-4.0.0.tar.gz',
|
'https://github.com/sahlberg/libnfs/archive/libnfs-5.0.1.tar.gz',
|
||||||
'6ee77e9fe220e2d3e3b1f53cfea04fb319828cc7dbb97dd9df09e46e901d797d',
|
'7ef445410b42f36b9bad426608b53ccb9ccca4101e545c383f564c11db672ca8',
|
||||||
'lib/libnfs.a',
|
'lib/libnfs.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -433,8 +433,7 @@ libnfs = AutotoolsProject(
|
|||||||
|
|
||||||
'--disable-utils', '--disable-examples',
|
'--disable-utils', '--disable-examples',
|
||||||
],
|
],
|
||||||
base='libnfs-libnfs-4.0.0',
|
base='libnfs-libnfs-5.0.1',
|
||||||
patches='src/lib/nfs/patches',
|
|
||||||
autoreconf=True,
|
autoreconf=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -445,7 +444,7 @@ jack = JackProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
boost = BoostProject(
|
boost = BoostProject(
|
||||||
'https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.bz2',
|
'https://boostorg.jfrog.io/artifactory/main/release/1.78.0/source/boost_1_78_0.tar.bz2',
|
||||||
'fc9f85fc030e233142908241af7a846e60630aa7388de9a5fafb1f3a26840854',
|
'8681f175d4bdb26c52222665793eef08490d7758529330f98d3b29dd0735bccc',
|
||||||
'include/boost/version.hpp',
|
'include/boost/version.hpp',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -53,19 +53,21 @@ pkgconfig = '{toolchain.pkg_config}'
|
|||||||
f.write(f"""
|
f.write(f"""
|
||||||
[properties]
|
[properties]
|
||||||
root = '{toolchain.install_prefix}'
|
root = '{toolchain.install_prefix}'
|
||||||
|
|
||||||
[built-in options]
|
|
||||||
c_args = {repr((toolchain.cppflags + ' ' + toolchain.cflags).split())}
|
|
||||||
c_link_args = {repr(toolchain.ldflags.split() + toolchain.libs.split())}
|
|
||||||
|
|
||||||
cpp_args = {repr((toolchain.cppflags + ' ' + toolchain.cxxflags).split())}
|
|
||||||
cpp_link_args = {repr(toolchain.ldflags.split() + toolchain.libs.split())}
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
if 'android' in toolchain.arch:
|
if 'android' in toolchain.arch:
|
||||||
f.write("""
|
f.write("""
|
||||||
# Keep Meson from executing Android-x86 test binariees
|
# Keep Meson from executing Android-x86 test binariees
|
||||||
needs_exe_wrapper = true
|
needs_exe_wrapper = true
|
||||||
|
""")
|
||||||
|
|
||||||
|
f.write(f"""
|
||||||
|
[built-in options]
|
||||||
|
c_args = {repr((toolchain.cppflags + ' ' + toolchain.cflags).split())}
|
||||||
|
c_link_args = {repr(toolchain.ldflags.split() + toolchain.libs.split())}
|
||||||
|
|
||||||
|
cpp_args = {repr((toolchain.cppflags + ' ' + toolchain.cxxflags).split())}
|
||||||
|
cpp_link_args = {repr(toolchain.ldflags.split() + toolchain.libs.split())}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
f.write(f"""
|
f.write(f"""
|
||||||
|
|||||||
@@ -48,15 +48,14 @@ LocateFileUri(const char *uri, const Client *client
|
|||||||
/* this path was relative to the music
|
/* this path was relative to the music
|
||||||
directory */
|
directory */
|
||||||
// TODO: don't use suffix.data() (ok for now because we know it's null-terminated)
|
// TODO: don't use suffix.data() (ok for now because we know it's null-terminated)
|
||||||
return LocatedUri(LocatedUri::Type::RELATIVE,
|
return {LocatedUri::Type::RELATIVE, suffix.data()};
|
||||||
suffix.data());
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (client != nullptr)
|
if (client != nullptr)
|
||||||
client->AllowFile(path);
|
client->AllowFile(path);
|
||||||
|
|
||||||
return LocatedUri(LocatedUri::Type::PATH, uri, std::move(path));
|
return {LocatedUri::Type::PATH, uri, std::move(path)};
|
||||||
}
|
}
|
||||||
|
|
||||||
static LocatedUri
|
static LocatedUri
|
||||||
@@ -90,8 +89,7 @@ LocateAbsoluteUri(UriPluginKind kind, const char *uri
|
|||||||
const auto suffix = storage->MapToRelativeUTF8(uri);
|
const auto suffix = storage->MapToRelativeUTF8(uri);
|
||||||
if (suffix.data() != nullptr)
|
if (suffix.data() != nullptr)
|
||||||
// TODO: don't use suffix.data() (ok for now because we know it's null-terminated)
|
// TODO: don't use suffix.data() (ok for now because we know it's null-terminated)
|
||||||
return LocatedUri(LocatedUri::Type::RELATIVE,
|
return {LocatedUri::Type::RELATIVE, suffix.data()};
|
||||||
suffix.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind == UriPluginKind::STORAGE &&
|
if (kind == UriPluginKind::STORAGE &&
|
||||||
@@ -99,7 +97,7 @@ LocateAbsoluteUri(UriPluginKind kind, const char *uri
|
|||||||
throw std::invalid_argument("Unsupported URI scheme");
|
throw std::invalid_argument("Unsupported URI scheme");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return LocatedUri(LocatedUri::Type::ABSOLUTE, uri);
|
return {LocatedUri::Type::ABSOLUTE, uri};
|
||||||
}
|
}
|
||||||
|
|
||||||
LocatedUri
|
LocatedUri
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
#include "PlaylistDatabase.hxx"
|
#include "PlaylistDatabase.hxx"
|
||||||
#include "db/PlaylistVector.hxx"
|
#include "db/PlaylistVector.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "io/LineReader.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "time/ChronoUtil.hxx"
|
#include "time/ChronoUtil.hxx"
|
||||||
#include "util/StringStrip.hxx"
|
#include "util/StringStrip.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
@@ -42,7 +42,7 @@ playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name)
|
playlist_metadata_load(LineReader &file, PlaylistVector &pv, const char *name)
|
||||||
{
|
{
|
||||||
PlaylistInfo pm(name);
|
PlaylistInfo pm(name);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
class PlaylistVector;
|
class PlaylistVector;
|
||||||
class BufferedOutputStream;
|
class BufferedOutputStream;
|
||||||
class TextFile;
|
class LineReader;
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv);
|
playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv);
|
||||||
@@ -33,6 +33,7 @@ playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv);
|
|||||||
* Throws #std::runtime_error on error.
|
* Throws #std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name);
|
playlist_metadata_load(LineReader &file, PlaylistVector &pv,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
#include "protocol/RangeArg.hxx"
|
#include "protocol/RangeArg.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "fs/io/TextFile.hxx"
|
||||||
#include "fs/io/FileOutputStream.hxx"
|
#include "io/FileOutputStream.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "config/Data.hxx"
|
#include "config/Data.hxx"
|
||||||
#include "config/Option.hxx"
|
#include "config/Option.hxx"
|
||||||
#include "config/Defaults.hxx"
|
#include "config/Defaults.hxx"
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
#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/io/FileOutputStream.hxx"
|
#include "io/FileOutputStream.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "util/UriExtract.hxx"
|
#include "util/UriExtract.hxx"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ enum class SingleMode : uint8_t {
|
|||||||
/**
|
/**
|
||||||
* Return the string representation of a #SingleMode.
|
* Return the string representation of a #SingleMode.
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::const]]
|
||||||
const char *
|
const char *
|
||||||
SingleToString(SingleMode mode) noexcept;
|
SingleToString(SingleMode mode) noexcept;
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
#include "db/plugins/simple/Song.hxx"
|
#include "db/plugins/simple/Song.hxx"
|
||||||
#include "song/DetachedSong.hxx"
|
#include "song/DetachedSong.hxx"
|
||||||
#include "TagSave.hxx"
|
#include "TagSave.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "io/LineReader.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "tag/ParseName.hxx"
|
#include "tag/ParseName.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "tag/Builder.hxx"
|
#include "tag/Builder.hxx"
|
||||||
@@ -85,7 +85,7 @@ song_save(BufferedOutputStream &os, const DetachedSong &song)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DetachedSong
|
DetachedSong
|
||||||
song_load(TextFile &file, const char *uri,
|
song_load(LineReader &file, const char *uri,
|
||||||
std::string *target_r)
|
std::string *target_r)
|
||||||
{
|
{
|
||||||
DetachedSong song(uri);
|
DetachedSong song(uri);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ struct Song;
|
|||||||
struct AudioFormat;
|
struct AudioFormat;
|
||||||
class DetachedSong;
|
class DetachedSong;
|
||||||
class BufferedOutputStream;
|
class BufferedOutputStream;
|
||||||
class TextFile;
|
class LineReader;
|
||||||
|
|
||||||
void
|
void
|
||||||
song_save(BufferedOutputStream &os, const Song &song);
|
song_save(BufferedOutputStream &os, const Song &song);
|
||||||
@@ -43,7 +43,7 @@ song_save(BufferedOutputStream &os, const DetachedSong &song);
|
|||||||
* Throws on error.
|
* Throws on error.
|
||||||
*/
|
*/
|
||||||
DetachedSong
|
DetachedSong
|
||||||
song_load(TextFile &file, const char *uri,
|
song_load(LineReader &file, const char *uri,
|
||||||
std::string *target_r=nullptr);
|
std::string *target_r=nullptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
#include "output/State.hxx"
|
#include "output/State.hxx"
|
||||||
#include "queue/PlaylistState.hxx"
|
#include "queue/PlaylistState.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "fs/io/TextFile.hxx"
|
||||||
#include "fs/io/FileOutputStream.hxx"
|
#include "io/FileOutputStream.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "storage/StorageState.hxx"
|
#include "storage/StorageState.hxx"
|
||||||
#include "Partition.hxx"
|
#include "Partition.hxx"
|
||||||
#include "Instance.hxx"
|
#include "Instance.hxx"
|
||||||
|
|||||||
@@ -21,12 +21,16 @@
|
|||||||
#include "TagStream.hxx"
|
#include "TagStream.hxx"
|
||||||
#include "TagFile.hxx"
|
#include "TagFile.hxx"
|
||||||
#include "tag/Generic.hxx"
|
#include "tag/Generic.hxx"
|
||||||
|
#include "song/LightSong.hxx"
|
||||||
|
#include "db/Interface.hxx"
|
||||||
#include "storage/StorageInterface.hxx"
|
#include "storage/StorageInterface.hxx"
|
||||||
#include "client/Client.hxx"
|
#include "client/Client.hxx"
|
||||||
#include "protocol/Ack.hxx"
|
#include "protocol/Ack.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
|
#include "util/ScopeExit.hxx"
|
||||||
|
#include "util/StringCompare.hxx"
|
||||||
#include "util/UriExtract.hxx"
|
#include "util/UriExtract.hxx"
|
||||||
#include "LocateUri.hxx"
|
#include "LocateUri.hxx"
|
||||||
|
|
||||||
@@ -51,10 +55,67 @@ TagScanFile(const Path path_fs, TagHandler &handler)
|
|||||||
ScanGenericTags(path_fs, handler);
|
ScanGenericTags(path_fs, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_DATABASE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collapse "../" prefixes in a URI relative to the specified base
|
||||||
|
* URI.
|
||||||
|
*/
|
||||||
|
static std::string
|
||||||
|
ResolveUri(std::string_view base, const char *relative)
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
const char *rest = StringAfterPrefix(relative, "../");
|
||||||
|
if (rest == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (base == ".")
|
||||||
|
throw ProtocolError(ACK_ERROR_NO_EXIST, "Bad real URI");
|
||||||
|
|
||||||
|
base = PathTraitsUTF8::GetParent(base);
|
||||||
|
relative = rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PathTraitsUTF8::Build(base, relative);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up the specified song in the database and return its
|
||||||
|
* (resolved) "real" URI.
|
||||||
|
*/
|
||||||
|
static std::string
|
||||||
|
GetRealSongUri(Client &client, std::string_view uri)
|
||||||
|
{
|
||||||
|
const auto &db = client.GetDatabaseOrThrow();
|
||||||
|
|
||||||
|
const auto *song = db.GetSong(uri);
|
||||||
|
if (song == nullptr)
|
||||||
|
throw ProtocolError(ACK_ERROR_NO_EXIST, "No such song");
|
||||||
|
|
||||||
|
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
||||||
|
|
||||||
|
if (song->real_uri == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return ResolveUri(PathTraitsUTF8::GetParent(uri), song->real_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
TagScanDatabase(Client &client, const char *uri, TagHandler &handler)
|
TagScanDatabase(Client &client, const char *uri, TagHandler &handler)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
|
const auto real_uri = GetRealSongUri(client, uri);
|
||||||
|
|
||||||
|
if (!real_uri.empty()) {
|
||||||
|
uri = real_uri.c_str();
|
||||||
|
|
||||||
|
// TODO: support absolute paths?
|
||||||
|
if (uri_has_scheme(uri))
|
||||||
|
return TagScanStream(uri, handler);
|
||||||
|
}
|
||||||
|
|
||||||
const Storage *storage = client.GetStorage();
|
const Storage *storage = client.GetStorage();
|
||||||
if (storage == nullptr) {
|
if (storage == nullptr) {
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "TagSave.hxx"
|
#include "TagSave.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
|
|
||||||
#define SONG_TIME "Time: "
|
#define SONG_TIME "Time: "
|
||||||
|
|
||||||
|
|||||||
@@ -160,8 +160,7 @@ find_stream_art(std::string_view directory, Mutex &mutex)
|
|||||||
static constexpr auto art_names = std::array {
|
static constexpr auto art_names = std::array {
|
||||||
"cover.png",
|
"cover.png",
|
||||||
"cover.jpg",
|
"cover.jpg",
|
||||||
"cover.tiff",
|
"cover.webp",
|
||||||
"cover.bmp",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for(const auto name : art_names) {
|
for(const auto name : art_names) {
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
#include "fs/List.hxx"
|
#include "fs/List.hxx"
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "fs/io/FileReader.hxx"
|
#include "io/FileReader.hxx"
|
||||||
#include "fs/io/BufferedReader.hxx"
|
#include "io/BufferedReader.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
#include "DatabaseSave.hxx"
|
#include "DatabaseSave.hxx"
|
||||||
#include "db/DatabaseLock.hxx"
|
#include "db/DatabaseLock.hxx"
|
||||||
#include "DirectorySave.hxx"
|
#include "DirectorySave.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "io/LineReader.hxx"
|
||||||
#include "tag/ParseName.hxx"
|
#include "tag/ParseName.hxx"
|
||||||
#include "tag/Settings.hxx"
|
#include "tag/Settings.hxx"
|
||||||
#include "fs/Charset.hxx"
|
#include "fs/Charset.hxx"
|
||||||
@@ -64,7 +64,7 @@ db_save_internal(BufferedOutputStream &os, const Directory &music_root)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
db_load_internal(TextFile &file, Directory &music_root)
|
db_load_internal(LineReader &file, Directory &music_root)
|
||||||
{
|
{
|
||||||
char *line;
|
char *line;
|
||||||
unsigned format = 0;
|
unsigned format = 0;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
struct Directory;
|
struct Directory;
|
||||||
class BufferedOutputStream;
|
class BufferedOutputStream;
|
||||||
class TextFile;
|
class LineReader;
|
||||||
|
|
||||||
void
|
void
|
||||||
db_save_internal(BufferedOutputStream &os, const Directory &root);
|
db_save_internal(BufferedOutputStream &os, const Directory &root);
|
||||||
@@ -31,6 +31,6 @@ db_save_internal(BufferedOutputStream &os, const Directory &root);
|
|||||||
* Throws #std::runtime_error on error.
|
* Throws #std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
db_load_internal(TextFile &file, Directory &root);
|
db_load_internal(LineReader &file, Directory &root);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
#include "SongSave.hxx"
|
#include "SongSave.hxx"
|
||||||
#include "song/DetachedSong.hxx"
|
#include "song/DetachedSong.hxx"
|
||||||
#include "PlaylistDatabase.hxx"
|
#include "PlaylistDatabase.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "io/LineReader.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "time/ChronoUtil.hxx"
|
#include "time/ChronoUtil.hxx"
|
||||||
#include "util/StringAPI.hxx"
|
#include "util/StringAPI.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
@@ -121,7 +121,7 @@ ParseLine(Directory &directory, const char *line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Directory *
|
static Directory *
|
||||||
directory_load_subdir(TextFile &file, Directory &parent, std::string_view name)
|
directory_load_subdir(LineReader &file, Directory &parent, std::string_view name)
|
||||||
{
|
{
|
||||||
if (parent.FindChild(name) != nullptr)
|
if (parent.FindChild(name) != nullptr)
|
||||||
throw FormatRuntimeError("Duplicate subdirectory '%.*s'",
|
throw FormatRuntimeError("Duplicate subdirectory '%.*s'",
|
||||||
@@ -152,7 +152,7 @@ directory_load_subdir(TextFile &file, Directory &parent, std::string_view name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
directory_load(TextFile &file, Directory &directory)
|
directory_load(LineReader &file, Directory &directory)
|
||||||
{
|
{
|
||||||
const char *line;
|
const char *line;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#define MPD_DIRECTORY_SAVE_HXX
|
#define MPD_DIRECTORY_SAVE_HXX
|
||||||
|
|
||||||
struct Directory;
|
struct Directory;
|
||||||
class TextFile;
|
class LineReader;
|
||||||
class BufferedOutputStream;
|
class BufferedOutputStream;
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -31,6 +31,6 @@ directory_save(BufferedOutputStream &os, const Directory &directory);
|
|||||||
* Throws #std::runtime_error on error.
|
* Throws #std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
directory_load(TextFile &file, Directory &directory);
|
directory_load(LineReader &file, Directory &directory);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
#include "db/DatabaseLock.hxx"
|
#include "db/DatabaseLock.hxx"
|
||||||
#include "db/DatabaseError.hxx"
|
#include "db/DatabaseError.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "fs/io/TextFile.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "fs/io/FileOutputStream.hxx"
|
#include "io/FileOutputStream.hxx"
|
||||||
#include "fs/FileInfo.hxx"
|
#include "fs/FileInfo.hxx"
|
||||||
#include "config/Block.hxx"
|
#include "config/Block.hxx"
|
||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
#ifdef ENABLE_ZLIB
|
#ifdef ENABLE_ZLIB
|
||||||
#include "fs/io/GzipOutputStream.hxx"
|
#include "lib/zlib/GzipOutputStream.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#ifndef MPD_DECODER_READER_HXX
|
#ifndef MPD_DECODER_READER_HXX
|
||||||
#define MPD_DECODER_READER_HXX
|
#define MPD_DECODER_READER_HXX
|
||||||
|
|
||||||
#include "fs/io/Reader.hxx"
|
#include "io/Reader.hxx"
|
||||||
|
|
||||||
class DecoderClient;
|
class DecoderClient;
|
||||||
class InputStream;
|
class InputStream;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
|
||||||
#include "FfmpegIo.hxx"
|
#include "FfmpegIo.hxx"
|
||||||
|
#include "libavutil/mem.h"
|
||||||
#include "../DecoderAPI.hxx"
|
#include "../DecoderAPI.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
|
|
||||||
@@ -35,7 +36,11 @@ AvioStream::~AvioStream()
|
|||||||
inline int
|
inline int
|
||||||
AvioStream::Read(void *dest, int size)
|
AvioStream::Read(void *dest, int size)
|
||||||
{
|
{
|
||||||
return decoder_read(client, input, dest, size);
|
const auto nbytes = decoder_read(client, input, dest, size);
|
||||||
|
if (nbytes == 0)
|
||||||
|
return AVERROR_EOF;
|
||||||
|
|
||||||
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int64_t
|
inline int64_t
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ ScanOpusTags(const void *data, size_t size,
|
|||||||
if (!r.Expect("OpusTags", 8))
|
if (!r.Expect("OpusTags", 8))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!handler.WantPair() && !handler.WantTag())
|
if (!handler.WantPair() && !handler.WantTag() &&
|
||||||
|
!handler.WantPicture())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!r.SkipString())
|
if (!r.SkipString())
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
#include "lib/icu/Converter.hxx"
|
#include "lib/icu/Converter.hxx"
|
||||||
#ifdef HAVE_SIDPLAYFP
|
#ifdef HAVE_SIDPLAYFP
|
||||||
#include "fs/io/FileReader.hxx"
|
#include "io/FileReader.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#endif
|
#endif
|
||||||
#include "util/StringFormat.hxx"
|
#include "util/StringFormat.hxx"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "ToOutputStream.hxx"
|
#include "ToOutputStream.hxx"
|
||||||
#include "EncoderInterface.hxx"
|
#include "EncoderInterface.hxx"
|
||||||
#include "fs/io/OutputStream.hxx"
|
#include "io/OutputStream.hxx"
|
||||||
|
|
||||||
void
|
void
|
||||||
EncoderToOutputStream(OutputStream &os, Encoder &encoder)
|
EncoderToOutputStream(OutputStream &os, Encoder &encoder)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "filter/Prepared.hxx"
|
#include "filter/Prepared.hxx"
|
||||||
#include "pcm/Buffer.hxx"
|
#include "pcm/Buffer.hxx"
|
||||||
#include "pcm/AudioFormat.hxx"
|
#include "pcm/AudioFormat.hxx"
|
||||||
#include "AudioCompress/compress.h"
|
#include "pcm/AudioCompress/compress.h"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/ConstBuffer.hxx"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ endif
|
|||||||
|
|
||||||
filter_plugins = static_library(
|
filter_plugins = static_library(
|
||||||
'filter_plugins',
|
'filter_plugins',
|
||||||
'../../AudioCompress/compress.c',
|
|
||||||
'NullFilterPlugin.cxx',
|
'NullFilterPlugin.cxx',
|
||||||
'TwoFilters.cxx',
|
'TwoFilters.cxx',
|
||||||
'AutoConvertFilterPlugin.cxx',
|
'AutoConvertFilterPlugin.cxx',
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
#ifdef USE_XDG
|
#ifdef USE_XDG
|
||||||
#include "util/StringStrip.hxx"
|
#include "util/StringStrip.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
#include "io/TextFile.hxx"
|
#include "fs/io/TextFile.hxx"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "TextFile.hxx"
|
#include "TextFile.hxx"
|
||||||
#include "FileReader.hxx"
|
#include "io/FileReader.hxx"
|
||||||
#include "AutoGunzipReader.hxx"
|
#include "io/BufferedReader.hxx"
|
||||||
#include "BufferedReader.hxx"
|
#include "lib/zlib/AutoGunzipReader.hxx"
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#ifndef MPD_TEXT_FILE_HXX
|
#ifndef MPD_TEXT_FILE_HXX
|
||||||
#define MPD_TEXT_FILE_HXX
|
#define MPD_TEXT_FILE_HXX
|
||||||
|
|
||||||
|
#include "io/LineReader.hxx"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -29,7 +30,7 @@ class FileReader;
|
|||||||
class AutoGunzipReader;
|
class AutoGunzipReader;
|
||||||
class BufferedReader;
|
class BufferedReader;
|
||||||
|
|
||||||
class TextFile {
|
class TextFile final : public LineReader {
|
||||||
const std::unique_ptr<FileReader> file_reader;
|
const std::unique_ptr<FileReader> file_reader;
|
||||||
|
|
||||||
#ifdef ENABLE_ZLIB
|
#ifdef ENABLE_ZLIB
|
||||||
@@ -45,14 +46,8 @@ public:
|
|||||||
|
|
||||||
~TextFile() noexcept;
|
~TextFile() noexcept;
|
||||||
|
|
||||||
/**
|
/* virtual methods from class LineReader */
|
||||||
* Reads a line from the input file, and strips trailing
|
char *ReadLine() override;
|
||||||
* space. There is a reasonable maximum line length, only to
|
|
||||||
* prevent denial of service.
|
|
||||||
*
|
|
||||||
* @return a pointer to the line, or nullptr on end-of-file
|
|
||||||
*/
|
|
||||||
char *ReadLine();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,12 +14,7 @@ fs_sources = [
|
|||||||
'CheckFile.cxx',
|
'CheckFile.cxx',
|
||||||
'LookupFile.cxx',
|
'LookupFile.cxx',
|
||||||
'DirectoryReader.cxx',
|
'DirectoryReader.cxx',
|
||||||
'io/PeekReader.cxx',
|
|
||||||
'io/FileReader.cxx',
|
|
||||||
'io/BufferedReader.cxx',
|
|
||||||
'io/TextFile.cxx',
|
'io/TextFile.cxx',
|
||||||
'io/FileOutputStream.cxx',
|
|
||||||
'io/BufferedOutputStream.cxx',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if is_windows
|
if is_windows
|
||||||
@@ -28,14 +23,6 @@ else
|
|||||||
shlwapi_dep = dependency('', required: false)
|
shlwapi_dep = dependency('', required: false)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if zlib_dep.found()
|
|
||||||
fs_sources += [
|
|
||||||
'io/GunzipReader.cxx',
|
|
||||||
'io/AutoGunzipReader.cxx',
|
|
||||||
'io/GzipOutputStream.cxx',
|
|
||||||
]
|
|
||||||
endif
|
|
||||||
|
|
||||||
fs = static_library(
|
fs = static_library(
|
||||||
'fs',
|
'fs',
|
||||||
fs_sources,
|
fs_sources,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "IcyInputStream.hxx"
|
#include "IcyInputStream.hxx"
|
||||||
#include "IcyMetaDataParser.hxx"
|
#include "tag/IcyMetaDataParser.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "util/UriExtract.hxx"
|
#include "util/UriExtract.hxx"
|
||||||
#include "util/UriQueryParser.hxx"
|
#include "util/UriQueryParser.hxx"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#ifndef MPD_INPUT_READER_HXX
|
#ifndef MPD_INPUT_READER_HXX
|
||||||
#define MPD_INPUT_READER_HXX
|
#define MPD_INPUT_READER_HXX
|
||||||
|
|
||||||
#include "fs/io/Reader.hxx"
|
#include "io/Reader.hxx"
|
||||||
|
|
||||||
class InputStream;
|
class InputStream;
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "../MaybeBufferedInputStream.hxx"
|
#include "../MaybeBufferedInputStream.hxx"
|
||||||
#include "../AsyncInputStream.hxx"
|
#include "../AsyncInputStream.hxx"
|
||||||
#include "../IcyInputStream.hxx"
|
#include "../IcyInputStream.hxx"
|
||||||
#include "IcyMetaDataParser.hxx"
|
#include "tag/IcyMetaDataParser.hxx"
|
||||||
#include "../InputPlugin.hxx"
|
#include "../InputPlugin.hxx"
|
||||||
#include "config/Block.hxx"
|
#include "config/Block.hxx"
|
||||||
#include "tag/Builder.hxx"
|
#include "tag/Builder.hxx"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include "../InputStream.hxx"
|
#include "../InputStream.hxx"
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "fs/FileInfo.hxx"
|
#include "fs/FileInfo.hxx"
|
||||||
#include "fs/io/FileReader.hxx"
|
#include "io/FileReader.hxx"
|
||||||
#include "io/FileDescriptor.hxx"
|
#include "io/FileDescriptor.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ if curl_dep.found()
|
|||||||
input_plugins_sources += [
|
input_plugins_sources += [
|
||||||
'CurlInputPlugin.cxx',
|
'CurlInputPlugin.cxx',
|
||||||
'../IcyInputStream.cxx',
|
'../IcyInputStream.cxx',
|
||||||
'../../IcyMetaDataParser.cxx',
|
'../../tag/IcyMetaDataParser.cxx',
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
33
src/io/LineReader.hxx
Normal file
33
src/io/LineReader.hxx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2021 The Music Player Daemon Project
|
||||||
|
* http://www.musicpd.org
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class LineReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Reads a line from the input file, and strips trailing
|
||||||
|
* space. There is a reasonable maximum line length, only to
|
||||||
|
* prevent denial of service.
|
||||||
|
*
|
||||||
|
* @return a pointer to the line, or nullptr on end-of-file
|
||||||
|
*/
|
||||||
|
virtual char *ReadLine() = 0;
|
||||||
|
};
|
||||||
@@ -2,6 +2,11 @@ io = static_library(
|
|||||||
'io',
|
'io',
|
||||||
'FileDescriptor.cxx',
|
'FileDescriptor.cxx',
|
||||||
'Open.cxx',
|
'Open.cxx',
|
||||||
|
'PeekReader.cxx',
|
||||||
|
'FileReader.cxx',
|
||||||
|
'BufferedReader.cxx',
|
||||||
|
'FileOutputStream.cxx',
|
||||||
|
'BufferedOutputStream.cxx',
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -45,10 +45,15 @@ class Operation {
|
|||||||
CancellableOperation *cancellable = nullptr;
|
CancellableOperation *cancellable = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Operation() noexcept = default;
|
||||||
|
|
||||||
~Operation() noexcept {
|
~Operation() noexcept {
|
||||||
CancelUring();
|
CancelUring();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operation(const Operation &) = delete;
|
||||||
|
Operation &operator=(const Operation &) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are we waiting for the operation to complete?
|
* Are we waiting for the operation to complete?
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#include "CancellableOperation.hxx"
|
#include "CancellableOperation.hxx"
|
||||||
#include "util/DeleteDisposer.hxx"
|
#include "util/DeleteDisposer.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace Uring {
|
namespace Uring {
|
||||||
|
|
||||||
Queue::Queue(unsigned entries, unsigned flags)
|
Queue::Queue(unsigned entries, unsigned flags)
|
||||||
@@ -46,6 +48,23 @@ Queue::~Queue() noexcept
|
|||||||
operations.clear_and_dispose(DeleteDisposer{});
|
operations.clear_and_dispose(DeleteDisposer{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct io_uring_sqe &
|
||||||
|
Queue::RequireSubmitEntry()
|
||||||
|
{
|
||||||
|
auto *sqe = GetSubmitEntry();
|
||||||
|
if (sqe == nullptr) {
|
||||||
|
/* the submit queue is full; submit it to the kernel
|
||||||
|
and try again */
|
||||||
|
Submit();
|
||||||
|
|
||||||
|
sqe = GetSubmitEntry();
|
||||||
|
if (sqe == nullptr)
|
||||||
|
throw std::runtime_error{"io_uring_get_sqe() failed"};
|
||||||
|
}
|
||||||
|
|
||||||
|
return *sqe;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Queue::AddPending(struct io_uring_sqe &sqe,
|
Queue::AddPending(struct io_uring_sqe &sqe,
|
||||||
Operation &operation) noexcept
|
Operation &operation) noexcept
|
||||||
|
|||||||
@@ -63,6 +63,14 @@ public:
|
|||||||
return ring.GetSubmitEntry();
|
return ring.GetSubmitEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like GetSubmitEntry(), but call Submit() if the submit
|
||||||
|
* queue is full.
|
||||||
|
*
|
||||||
|
* May throw exceptions if Submit() fails.
|
||||||
|
*/
|
||||||
|
struct io_uring_sqe &RequireSubmitEntry();
|
||||||
|
|
||||||
bool HasPending() const noexcept {
|
bool HasPending() const noexcept {
|
||||||
return !operations.empty();
|
return !operations.empty();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,14 +45,13 @@ ReadOperation::Start(Queue &queue, FileDescriptor fd, off_t offset,
|
|||||||
|
|
||||||
buffer = std::make_unique<std::byte[]>(size);
|
buffer = std::make_unique<std::byte[]>(size);
|
||||||
|
|
||||||
auto *s = queue.GetSubmitEntry();
|
auto &s = queue.RequireSubmitEntry();
|
||||||
assert(s != nullptr); // TODO: what if the submit queue is full?
|
|
||||||
|
|
||||||
iov.iov_base = buffer.get();
|
iov.iov_base = buffer.get();
|
||||||
iov.iov_len = size;
|
iov.iov_len = size;
|
||||||
|
|
||||||
io_uring_prep_readv(s, fd.Get(), &iov, 1, offset);
|
io_uring_prep_readv(&s, fd.Get(), &iov, 1, offset);
|
||||||
queue.Push(*s, *this);
|
queue.Push(s, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "Error.hxx"
|
#include "Error.hxx"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <alsa/error.h>
|
#include <alsa/error.h>
|
||||||
|
|
||||||
namespace Alsa {
|
namespace Alsa {
|
||||||
|
|||||||
@@ -50,4 +50,4 @@ MakeError(int error, const char *msg) noexcept
|
|||||||
return std::system_error(error, error_category, msg);
|
return std::system_error(error, error_category, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Avahi
|
} // namespace Alsa
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ CurlUnescape(CURL *curl, StringView src) noexcept
|
|||||||
int outlength;
|
int outlength;
|
||||||
CurlString tmp(curl_easy_unescape(curl, src.data, src.size,
|
CurlString tmp(curl_easy_unescape(curl, src.data, src.size,
|
||||||
&outlength));
|
&outlength));
|
||||||
return std::string(tmp.c_str(), outlength);
|
return {tmp.c_str(), size_t(outlength)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
Index: libnfs-libnfs-4.0.0/include/win32/win32_compat.h
|
|
||||||
===================================================================
|
|
||||||
--- libnfs-libnfs-4.0.0.orig/include/win32/win32_compat.h
|
|
||||||
+++ libnfs-libnfs-4.0.0/include/win32/win32_compat.h
|
|
||||||
@@ -133,7 +133,9 @@ struct pollfd {
|
|
||||||
|
|
||||||
/* Wrapper macros to call misc. functions win32 is missing */
|
|
||||||
#define poll(x, y, z) win32_poll(x, y, z)
|
|
||||||
+#ifndef __MINGW32__
|
|
||||||
#define snprintf sprintf_s
|
|
||||||
+#endif
|
|
||||||
#define inet_pton(x,y,z) win32_inet_pton(x,y,z)
|
|
||||||
#define open(x, y, z) _open(x, y, z)
|
|
||||||
#ifndef lseek
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
no_sprintf_s
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "OggSyncState.hxx"
|
#include "OggSyncState.hxx"
|
||||||
#include "fs/io/Reader.hxx"
|
#include "io/Reader.hxx"
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OggSyncState::Feed(size_t size)
|
OggSyncState::Feed(size_t size)
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
libflac_dep = dependency('flac', version: '>= 1.2', required: get_option('flac'))
|
libflac_dep = dependency('flac', version: '>= 1.2', required: get_option('flac'))
|
||||||
|
|
||||||
|
if is_windows
|
||||||
|
# Our Windows build generates a static libFLAC build
|
||||||
|
libflac_dep = declare_dependency(compile_args: '-DFLAC__NO_DLL',
|
||||||
|
dependencies: libflac_dep)
|
||||||
|
endif
|
||||||
|
|
||||||
libopus_dep = dependency('opus', required: get_option('opus'))
|
libopus_dep = dependency('opus', required: get_option('opus'))
|
||||||
|
|
||||||
if get_option('tremor').enabled()
|
if get_option('tremor').enabled()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#ifndef MPD_AUTO_GUNZIP_READER_HXX
|
#ifndef MPD_AUTO_GUNZIP_READER_HXX
|
||||||
#define MPD_AUTO_GUNZIP_READER_HXX
|
#define MPD_AUTO_GUNZIP_READER_HXX
|
||||||
|
|
||||||
#include "PeekReader.hxx"
|
#include "io/PeekReader.hxx"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
#ifndef GUNZIP_READER_HXX
|
#ifndef GUNZIP_READER_HXX
|
||||||
#define GUNZIP_READER_HXX
|
#define GUNZIP_READER_HXX
|
||||||
|
|
||||||
#include "Reader.hxx"
|
#include "io/Reader.hxx"
|
||||||
#include "util/StaticFifoBuffer.hxx"
|
#include "util/StaticFifoBuffer.hxx"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
#ifndef GZIP_OUTPUT_STREAM_HXX
|
#ifndef GZIP_OUTPUT_STREAM_HXX
|
||||||
#define GZIP_OUTPUT_STREAM_HXX
|
#define GZIP_OUTPUT_STREAM_HXX
|
||||||
|
|
||||||
#include "OutputStream.hxx"
|
#include "io/OutputStream.hxx"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
@@ -7,6 +7,9 @@ endif
|
|||||||
zlib = static_library(
|
zlib = static_library(
|
||||||
'zlib',
|
'zlib',
|
||||||
'Error.cxx',
|
'Error.cxx',
|
||||||
|
'GunzipReader.cxx',
|
||||||
|
'GzipOutputStream.cxx',
|
||||||
|
'AutoGunzipReader.cxx',
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
zlib_dep,
|
zlib_dep,
|
||||||
@@ -17,5 +20,6 @@ zlib_dep = declare_dependency(
|
|||||||
link_with: zlib,
|
link_with: zlib,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
zlib_dep,
|
zlib_dep,
|
||||||
|
io_dep,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "system/PeriodClock.hxx"
|
#include "system/PeriodClock.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "MultipleOutputs.hxx"
|
#include "MultipleOutputs.hxx"
|
||||||
#include "Domain.hxx"
|
#include "Domain.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|||||||
@@ -336,6 +336,8 @@ PipeWireOutput::Enable()
|
|||||||
throw MakeErrno("pw_thread_loop_new() failed");
|
throw MakeErrno("pw_thread_loop_new() failed");
|
||||||
|
|
||||||
pw_thread_loop_start(thread_loop);
|
pw_thread_loop_start(thread_loop);
|
||||||
|
|
||||||
|
stream = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "config/Path.hxx"
|
#include "config/Path.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
#include "fs/io/FileOutputStream.hxx"
|
#include "io/FileOutputStream.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
|
|
||||||
|
|||||||
@@ -471,6 +471,16 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UINT32 write_in_frames = buffer_size_in_frames;
|
UINT32 write_in_frames = buffer_size_in_frames;
|
||||||
|
DWORD mode = 0;
|
||||||
|
AtScopeExit(&) {
|
||||||
|
render_client->ReleaseBuffer(write_in_frames, mode);
|
||||||
|
|
||||||
|
if (!started) {
|
||||||
|
Start(client);
|
||||||
|
started = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!is_exclusive) {
|
if (!is_exclusive) {
|
||||||
UINT32 data_in_frames =
|
UINT32 data_in_frames =
|
||||||
GetCurrentPaddingFrames(client);
|
GetCurrentPaddingFrames(client);
|
||||||
@@ -481,7 +491,6 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BYTE *data;
|
BYTE *data;
|
||||||
DWORD mode = 0;
|
|
||||||
|
|
||||||
if (HRESULT result =
|
if (HRESULT result =
|
||||||
render_client->GetBuffer(write_in_frames, &data);
|
render_client->GetBuffer(write_in_frames, &data);
|
||||||
@@ -489,15 +498,6 @@ try {
|
|||||||
throw MakeHResultError(result, "Failed to get buffer");
|
throw MakeHResultError(result, "Failed to get buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
AtScopeExit(&) {
|
|
||||||
render_client->ReleaseBuffer(write_in_frames, mode);
|
|
||||||
|
|
||||||
if (!started) {
|
|
||||||
Start(client);
|
|
||||||
started = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const UINT32 write_size = write_in_frames * frame_size;
|
const UINT32 write_size = write_in_frames * frame_size;
|
||||||
UINT32 new_data_size = 0;
|
UINT32 new_data_size = 0;
|
||||||
new_data_size = spsc_buffer.pop(data, write_size);
|
new_data_size = spsc_buffer.pop(data, write_size);
|
||||||
|
|||||||
@@ -140,8 +140,7 @@ LibsampleratePcmResampler::Resample2(ConstBuffer<float> src)
|
|||||||
throw FormatRuntimeError("libsamplerate has failed: %s",
|
throw FormatRuntimeError("libsamplerate has failed: %s",
|
||||||
src_strerror(result));
|
src_strerror(result));
|
||||||
|
|
||||||
return ConstBuffer<float>(data.data_out,
|
return {data.data_out, size_t(data.output_frames_gen * channels)};
|
||||||
data.output_frames_gen * channels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ pcm_sources = [
|
|||||||
'GlueResampler.cxx',
|
'GlueResampler.cxx',
|
||||||
'FallbackResampler.cxx',
|
'FallbackResampler.cxx',
|
||||||
'ConfiguredResampler.cxx',
|
'ConfiguredResampler.cxx',
|
||||||
|
'AudioCompress/compress.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
libsamplerate_dep = dependency('samplerate', version: '>= 0.1.3', required: get_option('libsamplerate'))
|
libsamplerate_dep = dependency('samplerate', version: '>= 0.1.3', required: get_option('libsamplerate'))
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
#include "SingleMode.hxx"
|
#include "SingleMode.hxx"
|
||||||
#include "StateFileConfig.hxx"
|
#include "StateFileConfig.hxx"
|
||||||
#include "queue/QueueSave.hxx"
|
#include "queue/QueueSave.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "io/LineReader.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "player/Control.hxx"
|
#include "player/Control.hxx"
|
||||||
#include "util/CharUtil.hxx"
|
#include "util/CharUtil.hxx"
|
||||||
#include "util/StringAPI.hxx"
|
#include "util/StringAPI.hxx"
|
||||||
@@ -102,7 +102,7 @@ playlist_state_save(BufferedOutputStream &os, const struct playlist &playlist,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
playlist_state_load(TextFile &file, const SongLoader &song_loader,
|
playlist_state_load(LineReader &file, const SongLoader &song_loader,
|
||||||
struct playlist &playlist)
|
struct playlist &playlist)
|
||||||
{
|
{
|
||||||
const char *line = file.ReadLine();
|
const char *line = file.ReadLine();
|
||||||
@@ -128,7 +128,7 @@ playlist_state_load(TextFile &file, const SongLoader &song_loader,
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_state_restore(const StateFileConfig &config,
|
playlist_state_restore(const StateFileConfig &config,
|
||||||
const char *line, TextFile &file,
|
const char *line, LineReader &file,
|
||||||
const SongLoader &song_loader,
|
const SongLoader &song_loader,
|
||||||
struct playlist &playlist, PlayerControl &pc)
|
struct playlist &playlist, PlayerControl &pc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
struct StateFileConfig;
|
struct StateFileConfig;
|
||||||
struct playlist;
|
struct playlist;
|
||||||
class PlayerControl;
|
class PlayerControl;
|
||||||
class TextFile;
|
class LineReader;
|
||||||
class BufferedOutputStream;
|
class BufferedOutputStream;
|
||||||
class SongLoader;
|
class SongLoader;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ playlist_state_save(BufferedOutputStream &os, const playlist &playlist,
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_state_restore(const StateFileConfig &config,
|
playlist_state_restore(const StateFileConfig &config,
|
||||||
const char *line, TextFile &file,
|
const char *line, LineReader &file,
|
||||||
const SongLoader &song_loader,
|
const SongLoader &song_loader,
|
||||||
playlist &playlist, PlayerControl &pc);
|
playlist &playlist, PlayerControl &pc);
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
#include "song/DetachedSong.hxx"
|
#include "song/DetachedSong.hxx"
|
||||||
#include "SongSave.hxx"
|
#include "SongSave.hxx"
|
||||||
#include "playlist/PlaylistSong.hxx"
|
#include "playlist/PlaylistSong.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "io/LineReader.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ queue_save(BufferedOutputStream &os, const Queue &queue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static DetachedSong
|
static DetachedSong
|
||||||
LoadQueueSong(TextFile &file, const char *line)
|
LoadQueueSong(LineReader &file, const char *line)
|
||||||
{
|
{
|
||||||
std::unique_ptr<DetachedSong> song;
|
std::unique_ptr<DetachedSong> song;
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ LoadQueueSong(TextFile &file, const char *line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
queue_load_song(TextFile &file, const SongLoader &loader,
|
queue_load_song(LineReader &file, const SongLoader &loader,
|
||||||
const char *line, Queue &queue)
|
const char *line, Queue &queue)
|
||||||
{
|
{
|
||||||
if (queue.IsFull())
|
if (queue.IsFull())
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
struct Queue;
|
struct Queue;
|
||||||
class BufferedOutputStream;
|
class BufferedOutputStream;
|
||||||
class TextFile;
|
class LineReader;
|
||||||
class SongLoader;
|
class SongLoader;
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -39,7 +39,7 @@ queue_save(BufferedOutputStream &os, const Queue &queue);
|
|||||||
* Throws on error.
|
* Throws on error.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
queue_load_song(TextFile &file, const SongLoader &loader,
|
queue_load_song(LineReader &file, const SongLoader &loader,
|
||||||
const char *line, Queue &queue);
|
const char *line, Queue &queue);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
#include "StorageState.hxx"
|
#include "StorageState.hxx"
|
||||||
#include "lib/fmt/ExceptionFormatter.hxx"
|
#include "lib/fmt/ExceptionFormatter.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "io/LineReader.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "io/BufferedOutputStream.hxx"
|
||||||
#include "storage/Registry.hxx"
|
#include "storage/Registry.hxx"
|
||||||
#include "storage/CompositeStorage.hxx"
|
#include "storage/CompositeStorage.hxx"
|
||||||
#include "db/plugins/simple/SimpleDatabasePlugin.hxx"
|
#include "db/plugins/simple/SimpleDatabasePlugin.hxx"
|
||||||
@@ -73,7 +73,7 @@ storage_state_save(BufferedOutputStream &os, const Instance &instance)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
storage_state_restore(const char *line, TextFile &file, Instance &instance)
|
storage_state_restore(const char *line, LineReader &file, Instance &instance)
|
||||||
{
|
{
|
||||||
if (!StringStartsWith(line, MOUNT_STATE_BEGIN))
|
if (!StringStartsWith(line, MOUNT_STATE_BEGIN))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -27,13 +27,14 @@
|
|||||||
|
|
||||||
struct Instance;
|
struct Instance;
|
||||||
class BufferedOutputStream;
|
class BufferedOutputStream;
|
||||||
class TextFile;
|
class LineReader;
|
||||||
|
|
||||||
void
|
void
|
||||||
storage_state_save(BufferedOutputStream &os, const Instance &instance);
|
storage_state_save(BufferedOutputStream &os, const Instance &instance);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
storage_state_restore(const char *line, TextFile &file, Instance &instance);
|
storage_state_restore(const char *line, LineReader &file,
|
||||||
|
Instance &instance);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a hash number for the current state of the composite storage.
|
* Generates a hash number for the current state of the composite storage.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2018 Max Kellermann <max.kellermann@gmail.com>
|
* Copyright 2016-2021 Max Kellermann <max.kellermann@gmail.com>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -27,8 +27,7 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BIND_METHOD_HXX
|
#pragma once
|
||||||
#define BIND_METHOD_HXX
|
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -83,33 +82,15 @@ public:
|
|||||||
namespace BindMethodDetail {
|
namespace BindMethodDetail {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class which converts a signature type to a method pointer
|
* Helper class which introspects a method/function pointer type.
|
||||||
* type.
|
|
||||||
*
|
*
|
||||||
* @param T the wrapped class
|
* @param M the method/function pointer type
|
||||||
* @param S the function signature type (plain, without instance
|
|
||||||
* pointer)
|
|
||||||
*/
|
|
||||||
template<typename T, typename S>
|
|
||||||
struct MethodWithSignature;
|
|
||||||
|
|
||||||
template<typename T,
|
|
||||||
bool NoExcept,
|
|
||||||
typename R, typename... Args>
|
|
||||||
struct MethodWithSignature<T, R(Args...) noexcept(NoExcept)> {
|
|
||||||
typedef R (T::*method_pointer)(Args...) noexcept(NoExcept);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class which introspects a method pointer type.
|
|
||||||
*
|
|
||||||
* @param M the method pointer type
|
|
||||||
*/
|
*/
|
||||||
template<typename M>
|
template<typename M>
|
||||||
struct MethodSignatureHelper;
|
struct SignatureHelper;
|
||||||
|
|
||||||
template<typename R, bool NoExcept, typename T, typename... Args>
|
template<typename R, bool NoExcept, typename T, typename... Args>
|
||||||
struct MethodSignatureHelper<R (T::*)(Args...) noexcept(NoExcept)> {
|
struct SignatureHelper<R (T::*)(Args...) noexcept(NoExcept)> {
|
||||||
/**
|
/**
|
||||||
* The class which contains the given method (signature).
|
* The class which contains the given method (signature).
|
||||||
*/
|
*/
|
||||||
@@ -120,126 +101,48 @@ struct MethodSignatureHelper<R (T::*)(Args...) noexcept(NoExcept)> {
|
|||||||
* signature.
|
* signature.
|
||||||
*/
|
*/
|
||||||
typedef R plain_signature(Args...) noexcept(NoExcept);
|
typedef R plain_signature(Args...) noexcept(NoExcept);
|
||||||
|
|
||||||
|
typedef R (*function_pointer)(void *instance,
|
||||||
|
Args...) noexcept(NoExcept);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class which converts a plain function signature type to a
|
|
||||||
* wrapper function pointer type.
|
|
||||||
*/
|
|
||||||
template<typename S>
|
|
||||||
struct MethodWrapperWithSignature;
|
|
||||||
|
|
||||||
template<typename R, bool NoExcept, typename... Args>
|
template<typename R, bool NoExcept, typename... Args>
|
||||||
struct MethodWrapperWithSignature<R(Args...) noexcept(NoExcept)> {
|
struct SignatureHelper<R (*)(Args...) noexcept(NoExcept)> {
|
||||||
|
typedef R plain_signature(Args...) noexcept(NoExcept);
|
||||||
|
|
||||||
typedef R (*function_pointer)(void *instance,
|
typedef R (*function_pointer)(void *instance,
|
||||||
Args...) noexcept(NoExcept);
|
Args...) noexcept(NoExcept);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a wrapper function. Helper class for
|
* Generate a wrapper function.
|
||||||
* #BindMethodWrapperGenerator.
|
|
||||||
*
|
*
|
||||||
* @param T the containing class
|
* @param method the method/function pointer
|
||||||
* @param M the method pointer type
|
|
||||||
* @param method the method pointer
|
|
||||||
* @param R the return type
|
|
||||||
* @param Args the method arguments
|
|
||||||
*/
|
*/
|
||||||
template<typename T, bool NoExcept, typename M, M method, typename R, typename... Args>
|
template<typename M, auto method>
|
||||||
struct BindMethodWrapperGenerator2 {
|
struct WrapperGenerator;
|
||||||
|
|
||||||
|
template<typename T, bool NoExcept,
|
||||||
|
auto method, typename R, typename... Args>
|
||||||
|
struct WrapperGenerator<R (T::*)(Args...) noexcept(NoExcept), method> {
|
||||||
static R Invoke(void *_instance, Args... args) noexcept(NoExcept) {
|
static R Invoke(void *_instance, Args... args) noexcept(NoExcept) {
|
||||||
auto &t = *(T *)_instance;
|
auto &t = *(T *)_instance;
|
||||||
return (t.*method)(std::forward<Args>(args)...);
|
return (t.*method)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
template<auto function, bool NoExcept, typename R, typename... Args>
|
||||||
* Generate a wrapper function.
|
struct WrapperGenerator<R (*)(Args...) noexcept(NoExcept), function> {
|
||||||
*
|
|
||||||
* @param T the containing class
|
|
||||||
* @param M the method pointer type
|
|
||||||
* @param method the method pointer
|
|
||||||
* @param S the plain function signature type
|
|
||||||
*/
|
|
||||||
template<typename T, typename M, M method, typename S>
|
|
||||||
struct BindMethodWrapperGenerator;
|
|
||||||
|
|
||||||
template<typename T, bool NoExcept,
|
|
||||||
typename M, M method, typename R, typename... Args>
|
|
||||||
struct BindMethodWrapperGenerator<T, M, method, R(Args...) noexcept(NoExcept)>
|
|
||||||
: BindMethodWrapperGenerator2<T, NoExcept, M, method, R, Args...> {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename S,
|
|
||||||
typename MethodWithSignature<T, S>::method_pointer method>
|
|
||||||
typename MethodWrapperWithSignature<S>::function_pointer
|
|
||||||
MakeBindMethodWrapper() noexcept
|
|
||||||
{
|
|
||||||
return BindMethodWrapperGenerator<T, typename MethodWithSignature<T, S>::method_pointer, method, S>::Invoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class which introspects a function pointer type.
|
|
||||||
*
|
|
||||||
* @param S the function type
|
|
||||||
*/
|
|
||||||
template<typename S>
|
|
||||||
struct FunctionTraits;
|
|
||||||
|
|
||||||
template<typename R, bool NoExcept, typename... Args>
|
|
||||||
struct FunctionTraits<R(Args...) noexcept(NoExcept)> {
|
|
||||||
/**
|
|
||||||
* A function type which describes the "plain" function
|
|
||||||
* signature.
|
|
||||||
*/
|
|
||||||
typedef R function_type(Args...) noexcept(NoExcept);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A function pointer type which describes the "plain"
|
|
||||||
* function signature.
|
|
||||||
*/
|
|
||||||
typedef R (*pointer)(Args...) noexcept(NoExcept);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a wrapper function for a plain function which ignores the
|
|
||||||
* instance pointer. Helper class for
|
|
||||||
* #BindFunctionWrapperGenerator.
|
|
||||||
*
|
|
||||||
* @param F the function pointer type
|
|
||||||
* @param function the function pointer
|
|
||||||
* @param R the return type
|
|
||||||
* @param Args the function arguments
|
|
||||||
*/
|
|
||||||
template<bool NoExcept, typename F, F function, typename R, typename... Args>
|
|
||||||
struct BindFunctionWrapperGenerator2 {
|
|
||||||
static R Invoke(void *, Args... args) noexcept(NoExcept) {
|
static R Invoke(void *, Args... args) noexcept(NoExcept) {
|
||||||
return function(std::forward<Args>(args)...);
|
return function(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
template<auto method>
|
||||||
* Generate a wrapper function.
|
typename SignatureHelper<decltype(method)>::function_pointer
|
||||||
*
|
MakeWrapperFunction() noexcept
|
||||||
* @param S the plain function signature type
|
|
||||||
* @param P the plain function pointer type
|
|
||||||
* @param function the function pointer
|
|
||||||
*/
|
|
||||||
template<typename S, typename P, P function>
|
|
||||||
struct BindFunctionWrapperGenerator;
|
|
||||||
|
|
||||||
template<typename P, P function, bool NoExcept, typename R, typename... Args>
|
|
||||||
struct BindFunctionWrapperGenerator<R(Args...) noexcept(NoExcept), P, function>
|
|
||||||
: BindFunctionWrapperGenerator2<NoExcept, P, function, R, Args...> {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename T::pointer function>
|
|
||||||
typename MethodWrapperWithSignature<typename T::function_type>::function_pointer
|
|
||||||
MakeBindFunctionWrapper() noexcept
|
|
||||||
{
|
{
|
||||||
return BindFunctionWrapperGenerator<typename T::function_type,
|
return WrapperGenerator<decltype(method), method>::Invoke;
|
||||||
typename T::pointer,
|
|
||||||
function>::Invoke;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace BindMethodDetail */
|
} /* namespace BindMethodDetail */
|
||||||
@@ -247,18 +150,19 @@ MakeBindFunctionWrapper() noexcept
|
|||||||
/**
|
/**
|
||||||
* Construct a #BoundMethod instance.
|
* Construct a #BoundMethod instance.
|
||||||
*
|
*
|
||||||
* @param T the containing class
|
|
||||||
* @param S the plain function signature type
|
|
||||||
* @param method the method pointer
|
* @param method the method pointer
|
||||||
* @param instance the instance of #T to be bound
|
* @param instance the instance of #T to be bound
|
||||||
*/
|
*/
|
||||||
template<typename T, typename S,
|
template<auto method>
|
||||||
typename BindMethodDetail::MethodWithSignature<T, S>::method_pointer method>
|
constexpr auto
|
||||||
constexpr BoundMethod<S>
|
BindMethod(typename BindMethodDetail::SignatureHelper<decltype(method)>::class_type &instance) noexcept
|
||||||
BindMethod(T &_instance) noexcept
|
|
||||||
{
|
{
|
||||||
return BoundMethod<S>(&_instance,
|
using H = BindMethodDetail::SignatureHelper<decltype(method)>;
|
||||||
BindMethodDetail::MakeBindMethodWrapper<T, S, method>());
|
using plain_signature = typename H::plain_signature;
|
||||||
|
return BoundMethod<plain_signature>{
|
||||||
|
&instance,
|
||||||
|
BindMethodDetail::MakeWrapperFunction<method>(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -266,28 +170,29 @@ BindMethod(T &_instance) noexcept
|
|||||||
* constructs a #BoundMethod instance.
|
* constructs a #BoundMethod instance.
|
||||||
*/
|
*/
|
||||||
#define BIND_METHOD(instance, method) \
|
#define BIND_METHOD(instance, method) \
|
||||||
BindMethod<typename BindMethodDetail::MethodSignatureHelper<decltype(method)>::class_type, \
|
BindMethod<method>(instance)
|
||||||
typename BindMethodDetail::MethodSignatureHelper<decltype(method)>::plain_signature, \
|
|
||||||
method>(instance)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut wrapper for BIND_METHOD() which assumes "*this" is the
|
* Shortcut wrapper for BIND_METHOD() which assumes "*this" is the
|
||||||
* instance to be bound.
|
* instance to be bound.
|
||||||
*/
|
*/
|
||||||
#define BIND_THIS_METHOD(method) BIND_METHOD(*this, &std::remove_reference<decltype(*this)>::type::method)
|
#define BIND_THIS_METHOD(method) BIND_METHOD(*this, &std::remove_reference_t<decltype(*this)>::method)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a #BoundMethod instance for a plain function.
|
* Construct a #BoundMethod instance for a plain function.
|
||||||
*
|
*
|
||||||
* @param T the #FunctionTraits class
|
|
||||||
* @param function the function pointer
|
* @param function the function pointer
|
||||||
*/
|
*/
|
||||||
template<typename T, typename T::pointer function>
|
template<auto function>
|
||||||
constexpr BoundMethod<typename T::function_type>
|
constexpr auto
|
||||||
BindFunction() noexcept
|
BindFunction() noexcept
|
||||||
{
|
{
|
||||||
return BoundMethod<typename T::function_type>(nullptr,
|
using H = BindMethodDetail::SignatureHelper<decltype(function)>;
|
||||||
BindMethodDetail::MakeBindFunctionWrapper<T, function>());
|
using plain_signature = typename H::plain_signature;
|
||||||
|
return BoundMethod<plain_signature>{
|
||||||
|
nullptr,
|
||||||
|
BindMethodDetail::MakeWrapperFunction<function>(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -295,6 +200,4 @@ BindFunction() noexcept
|
|||||||
* #BoundMethod instance.
|
* #BoundMethod instance.
|
||||||
*/
|
*/
|
||||||
#define BIND_FUNCTION(function) \
|
#define BIND_FUNCTION(function) \
|
||||||
BindFunction<typename BindMethodDetail::FunctionTraits<decltype(function)>, &function>()
|
BindFunction<&function>()
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ protected:
|
|||||||
IntrusiveListNode siblings;
|
IntrusiveListNode siblings;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
IntrusiveListHook() noexcept = default;
|
||||||
|
|
||||||
|
IntrusiveListHook(const IntrusiveListHook &) = delete;
|
||||||
|
IntrusiveListHook &operator=(const IntrusiveListHook &) = delete;
|
||||||
|
|
||||||
void unlink() noexcept {
|
void unlink() noexcept {
|
||||||
siblings.next->prev = siblings.prev;
|
siblings.next->prev = siblings.prev;
|
||||||
siblings.prev->next = siblings.next;
|
siblings.prev->next = siblings.next;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user