Merge remote-tracking branches 'neheb/patch-2', 'neheb/con', 'neheb/cons', 'neheb/guruhg', 'neheb/r12R3', 'neheb/fefgheh' and 'neheb/rhgerg3453'
This commit is contained in:
commit
1e421cbcb2
6
NEWS
6
NEWS
|
@ -35,6 +35,12 @@ ver 0.22 (not yet released)
|
||||||
* switch to C++17
|
* switch to C++17
|
||||||
- GCC 7 or clang 4 (or newer) recommended
|
- GCC 7 or clang 4 (or newer) recommended
|
||||||
|
|
||||||
|
ver 0.21.20 (not yet released)
|
||||||
|
* decoder
|
||||||
|
- audiofile, ffmpeg, sndfile: handle MIME type "audio/wav"
|
||||||
|
- ffmpeg: fix playback of AIFF and TTA
|
||||||
|
- vorbis, opus: fix seeking in small files
|
||||||
|
|
||||||
ver 0.21.19 (2020/01/17)
|
ver 0.21.19 (2020/01/17)
|
||||||
* configuration
|
* configuration
|
||||||
- allow overriding top-level settings in includes
|
- allow overriding top-level settings in includes
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.musicpd"
|
package="org.musicpd"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:versionCode="42"
|
android:versionCode="43"
|
||||||
android:versionName="0.21.19">
|
android:versionName="0.21.20">
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,7 @@ public:
|
||||||
explicit ConfigLoader(ConfigData &_config) noexcept
|
explicit ConfigLoader(ConfigData &_config) noexcept
|
||||||
:config(_config) {}
|
:config(_config) {}
|
||||||
|
|
||||||
bool TryFile(const Path path);
|
bool TryFile(Path path);
|
||||||
bool TryFile(const AllocatedPath &base_path, Path path);
|
bool TryFile(const AllocatedPath &base_path, Path path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ class ZzipInputStream final : public InputStream {
|
||||||
ZZIP_FILE *const file;
|
ZZIP_FILE *const file;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ZzipInputStream(const std::shared_ptr<ZzipDir> _dir, const char *_uri,
|
ZzipInputStream(const std::shared_ptr<ZzipDir>& _dir, const char *_uri,
|
||||||
Mutex &_mutex,
|
Mutex &_mutex,
|
||||||
ZZIP_FILE *_file)
|
ZZIP_FILE *_file)
|
||||||
:InputStream(_uri, _mutex),
|
:InputStream(_uri, _mutex),
|
||||||
|
|
|
@ -82,7 +82,7 @@ ToAck(DatabaseErrorCode code) noexcept
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static enum ack
|
static enum ack
|
||||||
ToAck(std::exception_ptr ep) noexcept
|
ToAck(const std::exception_ptr& ep) noexcept
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
std::rethrow_exception(ep);
|
std::rethrow_exception(ep);
|
||||||
|
@ -113,7 +113,7 @@ ToAck(std::exception_ptr ep) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PrintError(Response &r, std::exception_ptr ep)
|
PrintError(Response &r, const std::exception_ptr& ep)
|
||||||
{
|
{
|
||||||
LogError(ep);
|
LogError(ep);
|
||||||
r.Error(ToAck(ep), GetFullMessage(ep).c_str());
|
r.Error(ToAck(ep), GetFullMessage(ep).c_str());
|
||||||
|
|
|
@ -28,6 +28,6 @@ class Response;
|
||||||
* Send the exception to the client.
|
* Send the exception to the client.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
PrintError(Response &r, std::exception_ptr ep);
|
PrintError(Response &r, const std::exception_ptr& ep);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -174,7 +174,7 @@ handle_status(Client &client, gcc_unused Request args, Response &r)
|
||||||
COMMAND_STATUS_BITRATE ": %u\n",
|
COMMAND_STATUS_BITRATE ": %u\n",
|
||||||
player_status.elapsed_time.RoundS(),
|
player_status.elapsed_time.RoundS(),
|
||||||
player_status.total_time.IsNegative()
|
player_status.total_time.IsNegative()
|
||||||
? 0u
|
? 0U
|
||||||
: unsigned(player_status.total_time.RoundS()),
|
: unsigned(player_status.total_time.RoundS()),
|
||||||
player_status.elapsed_time.ToDoubleS(),
|
player_status.elapsed_time.ToDoubleS(),
|
||||||
player_status.bit_rate);
|
player_status.bit_rate);
|
||||||
|
|
|
@ -50,7 +50,7 @@ template<typename T>
|
||||||
static auto
|
static auto
|
||||||
Append(std::forward_list<T> &list, T &&src)
|
Append(std::forward_list<T> &list, T &&src)
|
||||||
{
|
{
|
||||||
return list.emplace_after(FindLast(list), std::move(src));
|
return list.emplace_after(FindLast(list), std::forward<T>(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -39,7 +39,6 @@ search_add_to_playlist(const Database &db, const Storage *storage,
|
||||||
const DatabaseSelection &selection)
|
const DatabaseSelection &selection)
|
||||||
{
|
{
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
const auto f = std::bind(AddSong, storage,
|
const auto f = [=](auto && arg1) { return AddSong(storage, playlist_path_utf8, arg1); };
|
||||||
playlist_path_utf8, _1);
|
|
||||||
db.Visit(selection, f);
|
db.Visit(selection, f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,9 @@
|
||||||
#include <mpd/async.h>
|
#include <mpd/async.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
class LibmpdclientError final : public std::runtime_error {
|
class LibmpdclientError final : public std::runtime_error {
|
||||||
enum mpd_error code;
|
enum mpd_error code;
|
||||||
|
@ -447,7 +448,7 @@ ProxyDatabase::ProxyDatabase(EventLoop &_loop, DatabaseListener &_listener,
|
||||||
listener(_listener),
|
listener(_listener),
|
||||||
host(block.GetBlockValue("host", "")),
|
host(block.GetBlockValue("host", "")),
|
||||||
password(block.GetBlockValue("password", "")),
|
password(block.GetBlockValue("password", "")),
|
||||||
port(block.GetBlockValue("port", 0u)),
|
port(block.GetBlockValue("port", 0U)),
|
||||||
keepalive(block.GetBlockValue("keepalive", false))
|
keepalive(block.GetBlockValue("keepalive", false))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -516,7 +517,7 @@ ProxyDatabase::Connect()
|
||||||
(void)keepalive;
|
(void)keepalive;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
idle_received = ~0u;
|
idle_received = ~0U;
|
||||||
is_idle = false;
|
is_idle = false;
|
||||||
|
|
||||||
SocketMonitor::Open(SocketDescriptor(mpd_async_get_fd(mpd_connection_get_async(connection))));
|
SocketMonitor::Open(SocketDescriptor(mpd_async_get_fd(mpd_connection_get_async(connection))));
|
||||||
|
@ -674,15 +675,15 @@ ProxyDatabase::ReturnSong(const LightSong *_song) const noexcept
|
||||||
static void
|
static void
|
||||||
Visit(struct mpd_connection *connection, const char *uri,
|
Visit(struct mpd_connection *connection, const char *uri,
|
||||||
bool recursive, const SongFilter *filter,
|
bool recursive, const SongFilter *filter,
|
||||||
VisitDirectory visit_directory, VisitSong visit_song,
|
const VisitDirectory& visit_directory, const VisitSong& visit_song,
|
||||||
VisitPlaylist visit_playlist);
|
const VisitPlaylist& visit_playlist);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Visit(struct mpd_connection *connection,
|
Visit(struct mpd_connection *connection,
|
||||||
bool recursive, const SongFilter *filter,
|
bool recursive, const SongFilter *filter,
|
||||||
const struct mpd_directory *directory,
|
const struct mpd_directory *directory,
|
||||||
VisitDirectory visit_directory, VisitSong visit_song,
|
const VisitDirectory& visit_directory, const VisitSong& visit_song,
|
||||||
VisitPlaylist visit_playlist)
|
const VisitPlaylist& visit_playlist)
|
||||||
{
|
{
|
||||||
const char *path = mpd_directory_get_path(directory);
|
const char *path = mpd_directory_get_path(directory);
|
||||||
|
|
||||||
|
@ -697,7 +698,7 @@ Visit(struct mpd_connection *connection,
|
||||||
|
|
||||||
if (recursive)
|
if (recursive)
|
||||||
Visit(connection, path, recursive, filter,
|
Visit(connection, path, recursive, filter,
|
||||||
visit_directory, visit_song, visit_playlist);
|
visit_directory, std::move(visit_song), std::move(visit_playlist));
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
|
@ -710,7 +711,7 @@ Match(const SongFilter *filter, const LightSong &song) noexcept
|
||||||
static void
|
static void
|
||||||
Visit(const SongFilter *filter,
|
Visit(const SongFilter *filter,
|
||||||
const mpd_song *_song,
|
const mpd_song *_song,
|
||||||
VisitSong visit_song)
|
const VisitSong& visit_song)
|
||||||
{
|
{
|
||||||
if (!visit_song)
|
if (!visit_song)
|
||||||
return;
|
return;
|
||||||
|
@ -722,7 +723,7 @@ Visit(const SongFilter *filter,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Visit(const struct mpd_playlist *playlist,
|
Visit(const struct mpd_playlist *playlist,
|
||||||
VisitPlaylist visit_playlist)
|
const VisitPlaylist& visit_playlist)
|
||||||
{
|
{
|
||||||
if (!visit_playlist)
|
if (!visit_playlist)
|
||||||
return;
|
return;
|
||||||
|
@ -778,8 +779,8 @@ ReceiveEntities(struct mpd_connection *connection) noexcept
|
||||||
static void
|
static void
|
||||||
Visit(struct mpd_connection *connection, const char *uri,
|
Visit(struct mpd_connection *connection, const char *uri,
|
||||||
bool recursive, const SongFilter *filter,
|
bool recursive, const SongFilter *filter,
|
||||||
VisitDirectory visit_directory, VisitSong visit_song,
|
const VisitDirectory& visit_directory, const VisitSong& visit_song,
|
||||||
VisitPlaylist visit_playlist)
|
const VisitPlaylist& visit_playlist)
|
||||||
{
|
{
|
||||||
if (!mpd_send_list_meta(connection, uri))
|
if (!mpd_send_list_meta(connection, uri))
|
||||||
ThrowError(connection);
|
ThrowError(connection);
|
||||||
|
@ -813,7 +814,7 @@ Visit(struct mpd_connection *connection, const char *uri,
|
||||||
static void
|
static void
|
||||||
SearchSongs(struct mpd_connection *connection,
|
SearchSongs(struct mpd_connection *connection,
|
||||||
const DatabaseSelection &selection,
|
const DatabaseSelection &selection,
|
||||||
VisitSong visit_song)
|
const VisitSong& visit_song)
|
||||||
try {
|
try {
|
||||||
assert(selection.recursive);
|
assert(selection.recursive);
|
||||||
assert(visit_song);
|
assert(visit_song);
|
||||||
|
|
|
@ -220,8 +220,8 @@ Directory::Sort() noexcept
|
||||||
|
|
||||||
void
|
void
|
||||||
Directory::Walk(bool recursive, const SongFilter *filter,
|
Directory::Walk(bool recursive, const SongFilter *filter,
|
||||||
VisitDirectory visit_directory, VisitSong visit_song,
|
const VisitDirectory& visit_directory, const VisitSong& visit_song,
|
||||||
VisitPlaylist visit_playlist) const
|
const VisitPlaylist& visit_playlist) const
|
||||||
{
|
{
|
||||||
if (IsMount()) {
|
if (IsMount()) {
|
||||||
assert(IsEmpty());
|
assert(IsEmpty());
|
||||||
|
|
|
@ -284,8 +284,8 @@ public:
|
||||||
* Caller must lock #db_mutex.
|
* Caller must lock #db_mutex.
|
||||||
*/
|
*/
|
||||||
void Walk(bool recursive, const SongFilter *match,
|
void Walk(bool recursive, const SongFilter *match,
|
||||||
VisitDirectory visit_directory, VisitSong visit_song,
|
const VisitDirectory& visit_directory, const VisitSong& visit_song,
|
||||||
VisitPlaylist visit_playlist) const;
|
const VisitPlaylist& visit_playlist) const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
LightDirectory Export() const noexcept;
|
LightDirectory Export() const noexcept;
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "util/SplitString.hxx"
|
#include "util/SplitString.hxx"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -107,9 +108,9 @@ private:
|
||||||
void VisitServer(const ContentDirectoryService &server,
|
void VisitServer(const ContentDirectoryService &server,
|
||||||
std::forward_list<std::string> &&vpath,
|
std::forward_list<std::string> &&vpath,
|
||||||
const DatabaseSelection &selection,
|
const DatabaseSelection &selection,
|
||||||
VisitDirectory visit_directory,
|
const VisitDirectory& visit_directory,
|
||||||
VisitSong visit_song,
|
const VisitSong& visit_song,
|
||||||
VisitPlaylist visit_playlist) const;
|
const VisitPlaylist& visit_playlist) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run an UPnP search according to MPD parameters, and
|
* Run an UPnP search according to MPD parameters, and
|
||||||
|
@ -118,7 +119,7 @@ private:
|
||||||
void SearchSongs(const ContentDirectoryService &server,
|
void SearchSongs(const ContentDirectoryService &server,
|
||||||
const char *objid,
|
const char *objid,
|
||||||
const DatabaseSelection &selection,
|
const DatabaseSelection &selection,
|
||||||
VisitSong visit_song) const;
|
const VisitSong& visit_song) const;
|
||||||
|
|
||||||
UPnPDirContent SearchSongs(const ContentDirectoryService &server,
|
UPnPDirContent SearchSongs(const ContentDirectoryService &server,
|
||||||
const char *objid,
|
const char *objid,
|
||||||
|
@ -311,7 +312,7 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
|
||||||
static void
|
static void
|
||||||
visitSong(const UPnPDirObject &meta, const char *path,
|
visitSong(const UPnPDirObject &meta, const char *path,
|
||||||
const DatabaseSelection &selection,
|
const DatabaseSelection &selection,
|
||||||
VisitSong visit_song)
|
const VisitSong& visit_song)
|
||||||
{
|
{
|
||||||
if (!visit_song)
|
if (!visit_song)
|
||||||
return;
|
return;
|
||||||
|
@ -339,7 +340,7 @@ void
|
||||||
UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
|
UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
|
||||||
const char *objid,
|
const char *objid,
|
||||||
const DatabaseSelection &selection,
|
const DatabaseSelection &selection,
|
||||||
VisitSong visit_song) const
|
const VisitSong& visit_song) const
|
||||||
{
|
{
|
||||||
if (!visit_song)
|
if (!visit_song)
|
||||||
return;
|
return;
|
||||||
|
@ -440,13 +441,13 @@ UpnpDatabase::Namei(const ContentDirectoryService &server,
|
||||||
static void
|
static void
|
||||||
VisitItem(const UPnPDirObject &object, const char *uri,
|
VisitItem(const UPnPDirObject &object, const char *uri,
|
||||||
const DatabaseSelection &selection,
|
const DatabaseSelection &selection,
|
||||||
VisitSong visit_song, VisitPlaylist visit_playlist)
|
const VisitSong& visit_song, const VisitPlaylist& visit_playlist)
|
||||||
{
|
{
|
||||||
assert(object.type == UPnPDirObject::Type::ITEM);
|
assert(object.type == UPnPDirObject::Type::ITEM);
|
||||||
|
|
||||||
switch (object.item_class) {
|
switch (object.item_class) {
|
||||||
case UPnPDirObject::ItemClass::MUSIC:
|
case UPnPDirObject::ItemClass::MUSIC:
|
||||||
visitSong(object, uri, selection, visit_song);
|
visitSong(object, uri, selection, std::move(visit_song));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UPnPDirObject::ItemClass::PLAYLIST:
|
case UPnPDirObject::ItemClass::PLAYLIST:
|
||||||
|
@ -469,9 +470,9 @@ VisitItem(const UPnPDirObject &object, const char *uri,
|
||||||
static void
|
static void
|
||||||
VisitObject(const UPnPDirObject &object, const char *uri,
|
VisitObject(const UPnPDirObject &object, const char *uri,
|
||||||
const DatabaseSelection &selection,
|
const DatabaseSelection &selection,
|
||||||
VisitDirectory visit_directory,
|
const VisitDirectory& visit_directory,
|
||||||
VisitSong visit_song,
|
const VisitSong& visit_song,
|
||||||
VisitPlaylist visit_playlist)
|
const VisitPlaylist& visit_playlist)
|
||||||
{
|
{
|
||||||
switch (object.type) {
|
switch (object.type) {
|
||||||
case UPnPDirObject::Type::UNKNOWN:
|
case UPnPDirObject::Type::UNKNOWN:
|
||||||
|
@ -486,7 +487,7 @@ VisitObject(const UPnPDirObject &object, const char *uri,
|
||||||
|
|
||||||
case UPnPDirObject::Type::ITEM:
|
case UPnPDirObject::Type::ITEM:
|
||||||
VisitItem(object, uri, selection,
|
VisitItem(object, uri, selection,
|
||||||
visit_song, visit_playlist);
|
std::move(visit_song), std::move(visit_playlist));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,9 +498,9 @@ void
|
||||||
UpnpDatabase::VisitServer(const ContentDirectoryService &server,
|
UpnpDatabase::VisitServer(const ContentDirectoryService &server,
|
||||||
std::forward_list<std::string> &&vpath,
|
std::forward_list<std::string> &&vpath,
|
||||||
const DatabaseSelection &selection,
|
const DatabaseSelection &selection,
|
||||||
VisitDirectory visit_directory,
|
const VisitDirectory& visit_directory,
|
||||||
VisitSong visit_song,
|
const VisitSong& visit_song,
|
||||||
VisitPlaylist visit_playlist) const
|
const VisitPlaylist& visit_playlist) const
|
||||||
{
|
{
|
||||||
/* If the path begins with rootid, we know that this is a
|
/* If the path begins with rootid, we know that this is a
|
||||||
song, not a directory (because that's how we set things
|
song, not a directory (because that's how we set things
|
||||||
|
|
|
@ -41,7 +41,7 @@ adplug_init(const ConfigBlock &block)
|
||||||
FormatDebug(adplug_domain, "adplug %s",
|
FormatDebug(adplug_domain, "adplug %s",
|
||||||
CAdPlug::get_version().c_str());
|
CAdPlug::get_version().c_str());
|
||||||
|
|
||||||
sample_rate = block.GetPositiveValue("sample_rate", 48000u);
|
sample_rate = block.GetPositiveValue("sample_rate", 48000U);
|
||||||
CheckSampleRate(sample_rate);
|
CheckSampleRate(sample_rate);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -200,7 +200,7 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is)
|
||||||
AudioFileInputStream afis{&client, is};
|
AudioFileInputStream afis{&client, is};
|
||||||
AFvirtualfile *const vf = setup_virtual_fops(afis);
|
AFvirtualfile *const vf = setup_virtual_fops(afis);
|
||||||
|
|
||||||
const AFfilehandle fh = afOpenVirtualFile(vf, "r", nullptr);
|
auto fh = afOpenVirtualFile(vf, "r", nullptr);
|
||||||
if (fh == AF_NULL_FILEHANDLE)
|
if (fh == AF_NULL_FILEHANDLE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -269,6 +269,8 @@ static const char *const audiofile_suffixes[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const audiofile_mime_types[] = {
|
static const char *const audiofile_mime_types[] = {
|
||||||
|
"audio/wav",
|
||||||
|
"audio/aiff",
|
||||||
"audio/x-wav",
|
"audio/x-wav",
|
||||||
"audio/x-aiff",
|
"audio/x-aiff",
|
||||||
nullptr
|
nullptr
|
||||||
|
|
|
@ -150,6 +150,5 @@ dsdlib_tag_id3(InputStream &is, TagHandler &handler,
|
||||||
scan_id3_tag(id3_tag, handler);
|
scan_id3_tag(id3_tag, handler);
|
||||||
|
|
||||||
id3_tag_delete(id3_tag);
|
id3_tag_delete(id3_tag);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -213,7 +213,6 @@ dsdiff_handle_native_tag(DecoderClient *client, InputStream &is,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handler.OnTag(type, {label, length});
|
handler.OnTag(type, {label, length});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -231,7 +231,7 @@ faad_song_duration(DecoderBuffer &buffer, InputStream &is)
|
||||||
static NeAACDecHandle
|
static NeAACDecHandle
|
||||||
faad_decoder_new()
|
faad_decoder_new()
|
||||||
{
|
{
|
||||||
const NeAACDecHandle decoder = NeAACDecOpen();
|
auto decoder = NeAACDecOpen();
|
||||||
|
|
||||||
NeAACDecConfigurationPtr config =
|
NeAACDecConfigurationPtr config =
|
||||||
NeAACDecGetCurrentConfiguration(decoder);
|
NeAACDecGetCurrentConfiguration(decoder);
|
||||||
|
@ -324,7 +324,7 @@ faad_get_file_time(InputStream &is)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
faad_stream_decode(DecoderClient &client, InputStream &is,
|
faad_stream_decode(DecoderClient &client, InputStream &is,
|
||||||
DecoderBuffer &buffer, const NeAACDecHandle decoder)
|
DecoderBuffer &buffer, NeAACDecHandle decoder)
|
||||||
{
|
{
|
||||||
const auto total_time = faad_song_duration(buffer, is);
|
const auto total_time = faad_song_duration(buffer, is);
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ faad_stream_decode(DecoderClient &client, InputStream &is)
|
||||||
|
|
||||||
/* create the libfaad decoder */
|
/* create the libfaad decoder */
|
||||||
|
|
||||||
const NeAACDecHandle decoder = faad_decoder_new();
|
auto decoder = faad_decoder_new();
|
||||||
AtScopeExit(decoder) { NeAACDecClose(decoder); };
|
AtScopeExit(decoder) { NeAACDecClose(decoder); };
|
||||||
|
|
||||||
faad_stream_decode(client, is, buffer, decoder);
|
faad_stream_decode(client, is, buffer, decoder);
|
||||||
|
|
|
@ -698,7 +698,7 @@ static const char *const ffmpeg_mime_types[] = {
|
||||||
"audio/aac",
|
"audio/aac",
|
||||||
"audio/aacp",
|
"audio/aacp",
|
||||||
"audio/ac3",
|
"audio/ac3",
|
||||||
"audio/aiff"
|
"audio/aiff",
|
||||||
"audio/amr",
|
"audio/amr",
|
||||||
"audio/basic",
|
"audio/basic",
|
||||||
"audio/flac",
|
"audio/flac",
|
||||||
|
@ -711,12 +711,13 @@ static const char *const ffmpeg_mime_types[] = {
|
||||||
"audio/qcelp",
|
"audio/qcelp",
|
||||||
"audio/vorbis",
|
"audio/vorbis",
|
||||||
"audio/vorbis+ogg",
|
"audio/vorbis+ogg",
|
||||||
|
"audio/wav",
|
||||||
"audio/x-8svx",
|
"audio/x-8svx",
|
||||||
"audio/x-16sv",
|
"audio/x-16sv",
|
||||||
"audio/x-aac",
|
"audio/x-aac",
|
||||||
"audio/x-ac3",
|
"audio/x-ac3",
|
||||||
"audio/x-adx",
|
"audio/x-adx",
|
||||||
"audio/x-aiff"
|
"audio/x-aiff",
|
||||||
"audio/x-alaw",
|
"audio/x-alaw",
|
||||||
"audio/x-au",
|
"audio/x-au",
|
||||||
"audio/x-dca",
|
"audio/x-dca",
|
||||||
|
@ -736,7 +737,7 @@ static const char *const ffmpeg_mime_types[] = {
|
||||||
"audio/x-pn-realaudio",
|
"audio/x-pn-realaudio",
|
||||||
"audio/x-pn-multirate-realaudio",
|
"audio/x-pn-multirate-realaudio",
|
||||||
"audio/x-speex",
|
"audio/x-speex",
|
||||||
"audio/x-tta"
|
"audio/x-tta",
|
||||||
"audio/x-voc",
|
"audio/x-voc",
|
||||||
"audio/x-wav",
|
"audio/x-wav",
|
||||||
"audio/x-wma",
|
"audio/x-wma",
|
||||||
|
|
|
@ -77,7 +77,7 @@ fluidsynth_mpd_log_function(int level,
|
||||||
static bool
|
static bool
|
||||||
fluidsynth_init(const ConfigBlock &block)
|
fluidsynth_init(const ConfigBlock &block)
|
||||||
{
|
{
|
||||||
sample_rate = block.GetPositiveValue("sample_rate", 48000u);
|
sample_rate = block.GetPositiveValue("sample_rate", 48000U);
|
||||||
CheckSampleRate(sample_rate);
|
CheckSampleRate(sample_rate);
|
||||||
|
|
||||||
soundfont_path = block.GetBlockValue("soundfont",
|
soundfont_path = block.GetBlockValue("soundfont",
|
||||||
|
|
|
@ -186,7 +186,7 @@ HybridDsdDecode(DecoderClient &client, InputStream &input)
|
||||||
client.Ready(result.first, true, duration);
|
client.Ready(result.first, true, duration);
|
||||||
frame_size = result.first.GetFrameSize();
|
frame_size = result.first.GetFrameSize();
|
||||||
kbit_rate = frame_size * result.first.sample_rate /
|
kbit_rate = frame_size * result.first.sample_rate /
|
||||||
(1024u / 8u);
|
(1024U / 8U);
|
||||||
total_frames = result.second / frame_size;
|
total_frames = result.second / frame_size;
|
||||||
} catch (UnsupportedFile) {
|
} catch (UnsupportedFile) {
|
||||||
/* not a Hybrid-DSD file; let the next decoder plugin
|
/* not a Hybrid-DSD file; let the next decoder plugin
|
||||||
|
@ -236,7 +236,7 @@ HybridDsdDecode(DecoderClient &client, InputStream &input)
|
||||||
/* fill the buffer */
|
/* fill the buffer */
|
||||||
auto w = buffer.Write();
|
auto w = buffer.Write();
|
||||||
if (!w.empty()) {
|
if (!w.empty()) {
|
||||||
if (remaining_bytes < (1<<30ull) &&
|
if (remaining_bytes < (1<<30ULL) &&
|
||||||
w.size > size_t(remaining_bytes))
|
w.size > size_t(remaining_bytes))
|
||||||
w.size = remaining_bytes;
|
w.size = remaining_bytes;
|
||||||
|
|
||||||
|
|
|
@ -760,7 +760,7 @@ MadDecoder::DecodeFirstFrame(Tag *tag) noexcept
|
||||||
|
|
||||||
if (max_frames > 8 * 1024 * 1024) {
|
if (max_frames > 8 * 1024 * 1024) {
|
||||||
FormatWarning(mad_domain,
|
FormatWarning(mad_domain,
|
||||||
"mp3 file header indicates too many frames: %lu",
|
"mp3 file header indicates too many frames: %zu",
|
||||||
max_frames);
|
max_frames);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ mikmod_decoder_init(const ConfigBlock &block)
|
||||||
static char params[] = "";
|
static char params[] = "";
|
||||||
|
|
||||||
mikmod_loop = block.GetBlockValue("loop", false);
|
mikmod_loop = block.GetBlockValue("loop", false);
|
||||||
mikmod_sample_rate = block.GetPositiveValue("sample_rate", 44100u);
|
mikmod_sample_rate = block.GetPositiveValue("sample_rate", 44100U);
|
||||||
if (!audio_valid_sample_rate(mikmod_sample_rate))
|
if (!audio_valid_sample_rate(mikmod_sample_rate))
|
||||||
throw FormatRuntimeError("Invalid sample rate in line %d: %u",
|
throw FormatRuntimeError("Invalid sample rate in line %d: %u",
|
||||||
block.line, mikmod_sample_rate);
|
block.line, mikmod_sample_rate);
|
||||||
|
|
|
@ -45,8 +45,12 @@ OggDecoder::LoadEndPacket(ogg_packet &packet) const
|
||||||
DecoderReader reader(client, input_stream);
|
DecoderReader reader(client, input_stream);
|
||||||
OggSyncState sync2(reader);
|
OggSyncState sync2(reader);
|
||||||
OggStreamState stream2(GetSerialNo());
|
OggStreamState stream2(GetSerialNo());
|
||||||
|
|
||||||
|
/* passing synced=false because we're inside an
|
||||||
|
OggVisitor callback, and our InputStream may be in
|
||||||
|
the middle of an Ogg packet */
|
||||||
result = OggSeekFindEOS(sync2, stream2, packet,
|
result = OggSeekFindEOS(sync2, stream2, packet,
|
||||||
input_stream);
|
input_stream, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restore the previous file position */
|
/* restore the previous file position */
|
||||||
|
|
|
@ -127,7 +127,7 @@ SidplayGlobal::SidplayGlobal(const ConfigBlock &block)
|
||||||
if (!database_path.IsNull())
|
if (!database_path.IsNull())
|
||||||
songlength_database = sidplay_load_songlength_db(database_path);
|
songlength_database = sidplay_load_songlength_db(database_path);
|
||||||
|
|
||||||
default_songlength = block.GetPositiveValue("default_songlength", 0u);
|
default_songlength = block.GetPositiveValue("default_songlength", 0U);
|
||||||
|
|
||||||
default_genre = block.GetBlockValue("default_genre", "");
|
default_genre = block.GetBlockValue("default_genre", "");
|
||||||
|
|
||||||
|
@ -403,7 +403,7 @@ sidplay_file_decode(DecoderClient &client, Path path_fs)
|
||||||
const unsigned timebase = player.timebase();
|
const unsigned timebase = player.timebase();
|
||||||
#endif
|
#endif
|
||||||
const unsigned end = duration.IsNegative()
|
const unsigned end = duration.IsNegative()
|
||||||
? 0u
|
? 0U
|
||||||
: duration.ToScale<uint64_t>(timebase);
|
: duration.ToScale<uint64_t>(timebase);
|
||||||
|
|
||||||
DecoderCommand cmd;
|
DecoderCommand cmd;
|
||||||
|
|
|
@ -323,6 +323,8 @@ static const char *const sndfile_suffixes[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const sndfile_mime_types[] = {
|
static const char *const sndfile_mime_types[] = {
|
||||||
|
"audio/wav",
|
||||||
|
"audio/aiff",
|
||||||
"audio/x-wav",
|
"audio/x-wav",
|
||||||
"audio/x-aiff",
|
"audio/x-aiff",
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
PreparedFlacEncoder::PreparedFlacEncoder(const ConfigBlock &block)
|
PreparedFlacEncoder::PreparedFlacEncoder(const ConfigBlock &block)
|
||||||
:compression(block.GetBlockValue("compression", 5u))
|
:compression(block.GetBlockValue("compression", 5U))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ PreparedOpusEncoder::PreparedOpusEncoder(const ConfigBlock &block)
|
||||||
throw std::runtime_error("Invalid bit rate");
|
throw std::runtime_error("Invalid bit rate");
|
||||||
}
|
}
|
||||||
|
|
||||||
complexity = block.GetBlockValue("complexity", 10u);
|
complexity = block.GetBlockValue("complexity", 10U);
|
||||||
if (complexity > 10)
|
if (complexity > 10)
|
||||||
throw std::runtime_error("Invalid complexity");
|
throw std::runtime_error("Invalid complexity");
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,13 @@
|
||||||
#include <nfsc/libnfs-raw-nfs.h>
|
#include <nfsc/libnfs-raw-nfs.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IsFileNotFound(std::exception_ptr ep) noexcept
|
IsFileNotFound(std::exception_ptr ep) noexcept
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
std::rethrow_exception(ep);
|
std::rethrow_exception(std::move(ep));
|
||||||
} catch (const std::system_error &e) {
|
} catch (const std::system_error &e) {
|
||||||
return IsFileNotFound(e);
|
return IsFileNotFound(e);
|
||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
|
|
|
@ -112,7 +112,7 @@ input_cdio_init(EventLoop &, const ConfigBlock &block)
|
||||||
throw FormatRuntimeError("Unrecognized 'default_byte_order' setting: %s",
|
throw FormatRuntimeError("Unrecognized 'default_byte_order' setting: %s",
|
||||||
value);
|
value);
|
||||||
}
|
}
|
||||||
speed = block.GetBlockValue("speed",0u);
|
speed = block.GetBlockValue("speed",0U);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CdioUri {
|
struct CdioUri {
|
||||||
|
|
|
@ -364,7 +364,7 @@ input_curl_init(EventLoop &event_loop, const ConfigBlock &block)
|
||||||
http_200_aliases = curl_slist_append(http_200_aliases, "ICY 200 OK");
|
http_200_aliases = curl_slist_append(http_200_aliases, "ICY 200 OK");
|
||||||
|
|
||||||
proxy = block.GetBlockValue("proxy");
|
proxy = block.GetBlockValue("proxy");
|
||||||
proxy_port = block.GetBlockValue("proxy_port", 0u);
|
proxy_port = block.GetBlockValue("proxy_port", 0U);
|
||||||
proxy_user = block.GetBlockValue("proxy_user");
|
proxy_user = block.GetBlockValue("proxy_user");
|
||||||
proxy_password = block.GetBlockValue("proxy_password");
|
proxy_password = block.GetBlockValue("proxy_password");
|
||||||
|
|
||||||
|
@ -409,9 +409,9 @@ CurlInputStream::InitEasy()
|
||||||
request = new CurlRequest(**curl_init, GetURI(), *this);
|
request = new CurlRequest(**curl_init, GetURI(), *this);
|
||||||
|
|
||||||
request->SetOption(CURLOPT_HTTP200ALIASES, http_200_aliases);
|
request->SetOption(CURLOPT_HTTP200ALIASES, http_200_aliases);
|
||||||
request->SetOption(CURLOPT_FOLLOWLOCATION, 1l);
|
request->SetOption(CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
request->SetOption(CURLOPT_MAXREDIRS, 5l);
|
request->SetOption(CURLOPT_MAXREDIRS, 5L);
|
||||||
request->SetOption(CURLOPT_FAILONERROR, 1l);
|
request->SetOption(CURLOPT_FAILONERROR, 1L);
|
||||||
|
|
||||||
if (proxy != nullptr)
|
if (proxy != nullptr)
|
||||||
request->SetOption(CURLOPT_PROXY, proxy);
|
request->SetOption(CURLOPT_PROXY, proxy);
|
||||||
|
@ -424,8 +424,8 @@ CurlInputStream::InitEasy()
|
||||||
StringFormat<1024>("%s:%s", proxy_user,
|
StringFormat<1024>("%s:%s", proxy_user,
|
||||||
proxy_password).c_str());
|
proxy_password).c_str());
|
||||||
|
|
||||||
request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1l : 0l);
|
request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1L : 0L);
|
||||||
request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l);
|
request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2L : 0L);
|
||||||
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
|
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Failed(std::exception_ptr e) {
|
void Failed(const std::exception_ptr& e) {
|
||||||
SetInput(std::make_unique<FailingInputStream>(GetURI(), e,
|
SetInput(std::make_unique<FailingInputStream>(GetURI(), e,
|
||||||
mutex));
|
mutex));
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
static constexpr Domain tidal_domain("tidal");
|
static constexpr Domain tidal_domain("tidal");
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Failed(std::exception_ptr e) {
|
void Failed(const std::exception_ptr& e) {
|
||||||
SetInput(std::make_unique<FailingInputStream>(GetURI(), e,
|
SetInput(std::make_unique<FailingInputStream>(GetURI(), e,
|
||||||
mutex));
|
mutex));
|
||||||
}
|
}
|
||||||
|
@ -133,7 +134,7 @@ static bool
|
||||||
IsInvalidSession(std::exception_ptr e) noexcept
|
IsInvalidSession(std::exception_ptr e) noexcept
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
std::rethrow_exception(e);
|
std::rethrow_exception(std::move(e));
|
||||||
} catch (const TidalError &te) {
|
} catch (const TidalError &te) {
|
||||||
return te.IsInvalidSession();
|
return te.IsInvalidSession();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
|
@ -56,7 +56,7 @@ CurlRequest::CurlRequest(CurlGlobal &_global,
|
||||||
easy.SetUserAgent("Music Player Daemon " VERSION);
|
easy.SetUserAgent("Music Player Daemon " VERSION);
|
||||||
easy.SetHeaderFunction(_HeaderFunction, this);
|
easy.SetHeaderFunction(_HeaderFunction, this);
|
||||||
easy.SetWriteFunction(WriteFunction, this);
|
easy.SetWriteFunction(WriteFunction, this);
|
||||||
easy.SetOption(CURLOPT_NETRC, 1l);
|
easy.SetOption(CURLOPT_NETRC, 1L);
|
||||||
easy.SetErrorBuffer(error_buffer);
|
easy.SetErrorBuffer(error_buffer);
|
||||||
easy.SetNoProgress();
|
easy.SetNoProgress();
|
||||||
easy.SetNoSignal();
|
easy.SetNoSignal();
|
||||||
|
|
|
@ -167,7 +167,7 @@ ParseObjects(ODBus::ReadMessageIter &&i,
|
||||||
|
|
||||||
ForEachInterface(std::move(i), [&callback](const char *path, auto &&j){
|
ForEachInterface(std::move(i), [&callback](const char *path, auto &&j){
|
||||||
Object o(path);
|
Object o(path);
|
||||||
ParseObject(o, std::move(j));
|
ParseObject(o, std::forward<decltype(j)>(j));
|
||||||
if (o.IsValid())
|
if (o.IsValid())
|
||||||
callback(std::move(o));
|
callback(std::move(o));
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,7 +58,7 @@ try {
|
||||||
if (u.IsNull())
|
if (u.IsNull())
|
||||||
return AllocatedString<>::Duplicate(src);
|
return AllocatedString<>::Duplicate(src);
|
||||||
|
|
||||||
AllocatedArray<UChar> folded(u.size() * 2u);
|
AllocatedArray<UChar> folded(u.size() * 2U);
|
||||||
|
|
||||||
UErrorCode error_code = U_ZERO_ERROR;
|
UErrorCode error_code = U_ZERO_ERROR;
|
||||||
size_t folded_length = u_strFoldCase(folded.begin(), folded.size(),
|
size_t folded_length = u_strFoldCase(folded.begin(), folded.size(),
|
||||||
|
|
|
@ -37,7 +37,7 @@ ContentDirectoryService::ContentDirectoryService(const UPnPDevice &device,
|
||||||
m_modelName(device.modelName),
|
m_modelName(device.modelName),
|
||||||
m_rdreqcnt(200)
|
m_rdreqcnt(200)
|
||||||
{
|
{
|
||||||
if (!m_modelName.compare("MediaTomb")) {
|
if (m_modelName == "MediaTomb") {
|
||||||
// Readdir by 200 entries is good for most, but MediaTomb likes
|
// Readdir by 200 entries is good for most, but MediaTomb likes
|
||||||
// them really big. Actually 1000 is better but I don't dare
|
// them really big. Actually 1000 is better but I don't dare
|
||||||
m_rdreqcnt = 500;
|
m_rdreqcnt = 500;
|
||||||
|
|
|
@ -57,13 +57,14 @@ OggSeekPageAtOffset(OggSyncState &oy, ogg_stream_state &os, InputStream &is,
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OggSeekFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet,
|
OggSeekFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet,
|
||||||
InputStream &is)
|
InputStream &is, bool synced)
|
||||||
{
|
{
|
||||||
if (!is.KnownSize())
|
if (!is.KnownSize())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (is.GetRest() < 65536)
|
if (is.GetRest() < 65536)
|
||||||
return OggFindEOS(oy, os, packet);
|
return (synced || oy.ExpectPageSeekIn(os)) &&
|
||||||
|
OggFindEOS(oy, os, packet);
|
||||||
|
|
||||||
if (!is.CheapSeeking())
|
if (!is.CheapSeeking())
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -47,10 +47,13 @@ OggSeekPageAtOffset(OggSyncState &oy, ogg_stream_state &os, InputStream &is,
|
||||||
* Try to find the end-of-stream (EOS) packet. Seek to the end of the
|
* Try to find the end-of-stream (EOS) packet. Seek to the end of the
|
||||||
* file if necessary.
|
* file if necessary.
|
||||||
*
|
*
|
||||||
|
* @param synced is the #OggSyncState currently synced? If not, then
|
||||||
|
* we need to use ogg_sync_pageseek() instead of ogg_sync_pageout(),
|
||||||
|
* which is more expensive
|
||||||
* @return true if the EOS packet was found
|
* @return true if the EOS packet was found
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
OggSeekFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet,
|
OggSeekFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet,
|
||||||
InputStream &is);
|
InputStream &is, bool synced=true);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,7 +43,7 @@ OggSyncState::ExpectPage(ogg_page &page)
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
start_offset = offset;
|
start_offset = offset;
|
||||||
offset += r;
|
offset += page.header_len + page.body_len;
|
||||||
}
|
}
|
||||||
return r > 0;
|
return r > 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ UdisksNeighborExplorer::HandleMessage(DBusConnection *, DBusMessage *message) no
|
||||||
dbus_message_has_signature(message, InterfacesAddedType::value)) {
|
dbus_message_has_signature(message, InterfacesAddedType::value)) {
|
||||||
RecurseInterfaceDictEntry(ReadMessageIter(*message), [this](const char *path, auto &&i){
|
RecurseInterfaceDictEntry(ReadMessageIter(*message), [this](const char *path, auto &&i){
|
||||||
UDisks2::Object o(path);
|
UDisks2::Object o(path);
|
||||||
UDisks2::ParseObject(o, std::move(i));
|
UDisks2::ParseObject(o, std::forward<decltype(i)>(i));
|
||||||
if (o.IsValid())
|
if (o.IsValid())
|
||||||
this->Insert(std::move(o));
|
this->Insert(std::move(o));
|
||||||
});
|
});
|
||||||
|
|
|
@ -116,7 +116,7 @@ AudioOutputControl::GetMixer() const noexcept
|
||||||
return output ? output->mixer : nullptr;
|
return output ? output->mixer : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, std::string>
|
std::map<std::string, std::string>
|
||||||
AudioOutputControl::GetAttributes() const noexcept
|
AudioOutputControl::GetAttributes() const noexcept
|
||||||
{
|
{
|
||||||
return output
|
return output
|
||||||
|
|
|
@ -357,7 +357,7 @@ public:
|
||||||
|
|
||||||
void BeginDestroy() noexcept;
|
void BeginDestroy() noexcept;
|
||||||
|
|
||||||
const std::map<std::string, std::string> GetAttributes() const noexcept;
|
std::map<std::string, std::string> GetAttributes() const noexcept;
|
||||||
void SetAttribute(std::string &&name, std::string &&value);
|
void SetAttribute(std::string &&name, std::string &&value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -39,7 +39,7 @@ FilteredAudioOutput::SupportsPause() const noexcept
|
||||||
return output->SupportsPause();
|
return output->SupportsPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, std::string>
|
std::map<std::string, std::string>
|
||||||
FilteredAudioOutput::GetAttributes() const noexcept
|
FilteredAudioOutput::GetAttributes() const noexcept
|
||||||
{
|
{
|
||||||
return output->GetAttributes();
|
return output->GetAttributes();
|
||||||
|
|
|
@ -170,7 +170,7 @@ public:
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool SupportsPause() const noexcept;
|
bool SupportsPause() const noexcept;
|
||||||
|
|
||||||
const std::map<std::string, std::string> GetAttributes() const noexcept;
|
std::map<std::string, std::string> GetAttributes() const noexcept;
|
||||||
void SetAttribute(std::string &&name, std::string &&value);
|
void SetAttribute(std::string &&name, std::string &&value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -64,7 +64,7 @@ public:
|
||||||
*
|
*
|
||||||
* This method must be thread-safe.
|
* This method must be thread-safe.
|
||||||
*/
|
*/
|
||||||
virtual const std::map<std::string, std::string> GetAttributes() const noexcept {
|
virtual std::map<std::string, std::string> GetAttributes() const noexcept {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::map<std::string, std::string> GetAttributes() const noexcept override;
|
std::map<std::string, std::string> GetAttributes() const noexcept override;
|
||||||
void SetAttribute(std::string &&name, std::string &&value) override;
|
void SetAttribute(std::string &&name, std::string &&value) override;
|
||||||
|
|
||||||
void Enable() override;
|
void Enable() override;
|
||||||
|
@ -404,7 +404,7 @@ AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
|
||||||
#endif
|
#endif
|
||||||
buffer_time(block.GetPositiveValue("buffer_time",
|
buffer_time(block.GetPositiveValue("buffer_time",
|
||||||
MPD_ALSA_BUFFER_TIME_US)),
|
MPD_ALSA_BUFFER_TIME_US)),
|
||||||
period_time(block.GetPositiveValue("period_time", 0u))
|
period_time(block.GetPositiveValue("period_time", 0U))
|
||||||
{
|
{
|
||||||
#ifdef SND_PCM_NO_AUTO_RESAMPLE
|
#ifdef SND_PCM_NO_AUTO_RESAMPLE
|
||||||
if (!block.GetBlockValue("auto_resample", true))
|
if (!block.GetBlockValue("auto_resample", true))
|
||||||
|
@ -427,7 +427,7 @@ AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
|
||||||
allowed_formats = Alsa::AllowedFormat::ParseList(allowed_formats_string);
|
allowed_formats = Alsa::AllowedFormat::ParseList(allowed_formats_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, std::string>
|
std::map<std::string, std::string>
|
||||||
AlsaOutput::GetAttributes() const noexcept
|
AlsaOutput::GetAttributes() const noexcept
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> lock(attributes_mutex);
|
const std::lock_guard<Mutex> lock(attributes_mutex);
|
||||||
|
|
|
@ -101,7 +101,7 @@ MakeAoError()
|
||||||
|
|
||||||
AoOutput::AoOutput(const ConfigBlock &block)
|
AoOutput::AoOutput(const ConfigBlock &block)
|
||||||
:AudioOutput(0),
|
:AudioOutput(0),
|
||||||
write_size(block.GetPositiveValue("write_size", 1024u))
|
write_size(block.GetPositiveValue("write_size", 1024U))
|
||||||
{
|
{
|
||||||
const char *value = block.GetBlockValue("driver", "default");
|
const char *value = block.GetBlockValue("driver", "default");
|
||||||
if (StringIsEqual(value, "default"))
|
if (StringIsEqual(value, "default"))
|
||||||
|
|
|
@ -247,7 +247,7 @@ JackOutput::JackOutput(const ConfigBlock &block)
|
||||||
num_source_ports, num_destination_ports,
|
num_source_ports, num_destination_ports,
|
||||||
block.line);
|
block.line);
|
||||||
|
|
||||||
ringbuffer_size = block.GetPositiveValue("ringbuffer_size", 32768u);
|
ringbuffer_size = block.GetPositiveValue("ringbuffer_size", 32768U);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline jack_nframes_t
|
inline jack_nframes_t
|
||||||
|
|
|
@ -99,7 +99,7 @@ ShoutOutput::ShoutOutput(const ConfigBlock &block)
|
||||||
{
|
{
|
||||||
const char *host = require_block_string(block, "host");
|
const char *host = require_block_string(block, "host");
|
||||||
const char *mount = require_block_string(block, "mount");
|
const char *mount = require_block_string(block, "mount");
|
||||||
unsigned port = block.GetBlockValue("port", 0u);
|
unsigned port = block.GetBlockValue("port", 0U);
|
||||||
if (port == 0)
|
if (port == 0)
|
||||||
throw std::runtime_error("shout port must be configured");
|
throw std::runtime_error("shout port must be configured");
|
||||||
|
|
||||||
|
|
|
@ -50,11 +50,11 @@ HttpdOutput::HttpdOutput(EventLoop &_loop, const ConfigBlock &block)
|
||||||
genre = block.GetBlockValue("genre", "Set genre in config");
|
genre = block.GetBlockValue("genre", "Set genre in config");
|
||||||
website = block.GetBlockValue("website", "Set website in config");
|
website = block.GetBlockValue("website", "Set website in config");
|
||||||
|
|
||||||
clients_max = block.GetBlockValue("max_clients", 0u);
|
clients_max = block.GetBlockValue("max_clients", 0U);
|
||||||
|
|
||||||
/* set up bind_to_address */
|
/* set up bind_to_address */
|
||||||
|
|
||||||
ServerSocketAddGeneric(*this, block.GetBlockValue("bind_to_address"), block.GetBlockValue("port", 8000u));
|
ServerSocketAddGeneric(*this, block.GetBlockValue("bind_to_address"), block.GetBlockValue("port", 8000U));
|
||||||
|
|
||||||
/* determine content type */
|
/* determine content type */
|
||||||
content_type = prepared_encoder->GetMimeType();
|
content_type = prepared_encoder->GetMimeType();
|
||||||
|
|
|
@ -94,5 +94,5 @@ DsdToDopConverter::Convert(ConstBuffer<uint8_t> src) noexcept
|
||||||
{
|
{
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return rest_buffer.Process<uint32_t>(buffer, src, 2 * channels,
|
return rest_buffer.Process<uint32_t>(buffer, src, 2 * channels,
|
||||||
std::bind(DsdToDop, _1, _2, _3, channels));
|
[=](auto && arg1, auto && arg2, auto && arg3) { return DsdToDop(arg1, arg2, arg3, channels); });
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,5 +65,5 @@ Dsd16Converter::Convert(ConstBuffer<uint8_t> src) noexcept
|
||||||
{
|
{
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return rest_buffer.Process<uint16_t>(buffer, src, channels,
|
return rest_buffer.Process<uint16_t>(buffer, src, channels,
|
||||||
std::bind(Dsd8To16, _1, _2, _3, channels));
|
[=](auto && arg1, auto && arg2, auto && arg3) { return Dsd8To16(arg1, arg2, arg3, channels); });
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,5 +67,5 @@ Dsd32Converter::Convert(ConstBuffer<uint8_t> src) noexcept
|
||||||
{
|
{
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return rest_buffer.Process<uint32_t>(buffer, src, channels,
|
return rest_buffer.Process<uint32_t>(buffer, src, channels,
|
||||||
std::bind(Dsd8To32, _1, _2, _3, channels));
|
[=](auto && arg1, auto && arg2, auto && arg3) { return Dsd8To32(arg1, arg2, arg3, channels); });
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,8 +261,8 @@ public:
|
||||||
CommonExpatParser(ExpatNamespaceSeparator{'|'})
|
CommonExpatParser(ExpatNamespaceSeparator{'|'})
|
||||||
{
|
{
|
||||||
request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
||||||
request.SetOption(CURLOPT_FOLLOWLOCATION, 1l);
|
request.SetOption(CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
request.SetOption(CURLOPT_MAXREDIRS, 1l);
|
request.SetOption(CURLOPT_MAXREDIRS, 1L);
|
||||||
|
|
||||||
request_headers.Append(StringFormat<40>("depth: %u", depth));
|
request_headers.Append(StringFormat<40>("depth: %u", depth));
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ struct ApeFooter {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
tag_ape_scan(InputStream &is, ApeTagCallback callback)
|
tag_ape_scan(InputStream &is, const ApeTagCallback& callback)
|
||||||
try {
|
try {
|
||||||
std::unique_lock<Mutex> lock(is.mutex);
|
std::unique_lock<Mutex> lock(is.mutex);
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,6 @@ typedef std::function<bool(unsigned long flags, const char *key,
|
||||||
* present
|
* present
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
tag_ape_scan(InputStream &is, ApeTagCallback callback);
|
tag_ape_scan(InputStream &is, const ApeTagCallback& callback);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -54,14 +54,14 @@ tag_ape_import_item(unsigned long flags,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (handler.WantPair())
|
if (handler.WantPair())
|
||||||
for (const auto &i : IterableSplitString(value, '\0'))
|
for (const auto i : IterableSplitString(value, '\0'))
|
||||||
handler.OnPair(key, i);
|
handler.OnPair(key, i);
|
||||||
|
|
||||||
TagType type = tag_ape_name_parse(key);
|
TagType type = tag_ape_name_parse(key);
|
||||||
if (type == TAG_NUM_OF_ITEM_TYPES)
|
if (type == TAG_NUM_OF_ITEM_TYPES)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (const auto &i : IterableSplitString(value, '\0'))
|
for (const auto i : IterableSplitString(value, '\0'))
|
||||||
handler.OnTag(type, i);
|
handler.OnTag(type, i);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -204,7 +204,7 @@ struct CheckSequenceUTF8 {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct CheckSequenceUTF8<0u> {
|
struct CheckSequenceUTF8<0U> {
|
||||||
constexpr bool operator()(gcc_unused const char *p) const noexcept {
|
constexpr bool operator()(gcc_unused const char *p) const noexcept {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ InnerSequenceLengthUTF8(const char *p) noexcept
|
||||||
{
|
{
|
||||||
return CheckSequenceUTF8<L>()(p)
|
return CheckSequenceUTF8<L>()(p)
|
||||||
? L + 1
|
? L + 1
|
||||||
: 0u;
|
: 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
|
|
@ -28,15 +28,15 @@
|
||||||
|
|
||||||
void
|
void
|
||||||
DumpDecoderClient::Ready(const AudioFormat audio_format,
|
DumpDecoderClient::Ready(const AudioFormat audio_format,
|
||||||
gcc_unused bool seekable,
|
bool seekable,
|
||||||
SignedSongTime duration) noexcept
|
SignedSongTime duration) noexcept
|
||||||
{
|
{
|
||||||
assert(!initialized);
|
assert(!initialized);
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
fprintf(stderr, "audio_format=%s duration=%f\n",
|
fprintf(stderr, "audio_format=%s duration=%f seekable=%d\n",
|
||||||
ToString(audio_format).c_str(),
|
ToString(audio_format).c_str(),
|
||||||
duration.ToDoubleS());
|
duration.ToDoubleS(), seekable);
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ DumpDecoderClient::SubmitData(gcc_unused InputStream *is,
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_unused ssize_t nbytes = write(STDOUT_FILENO, data, datalen);
|
gcc_unused ssize_t nbytes = write(STDOUT_FILENO, data, datalen);
|
||||||
return DecoderCommand::NONE;
|
return GetCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
DecoderCommand
|
DecoderCommand
|
||||||
|
@ -113,7 +113,7 @@ DumpDecoderClient::SubmitTag(gcc_unused InputStream *is,
|
||||||
for (const auto &i : tag)
|
for (const auto &i : tag)
|
||||||
fprintf(stderr, " %s=%s\n", tag_item_names[i.type], i.value);
|
fprintf(stderr, " %s=%s\n", tag_item_names[i.type], i.value);
|
||||||
|
|
||||||
return DecoderCommand::NONE;
|
return GetCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
* A #DecoderClient implementation which dumps metadata to stderr and
|
* A #DecoderClient implementation which dumps metadata to stderr and
|
||||||
* decoded data to stdout.
|
* decoded data to stdout.
|
||||||
*/
|
*/
|
||||||
class DumpDecoderClient final : public DecoderClient {
|
class DumpDecoderClient : public DecoderClient {
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
uint16_t prev_kbit_rate = 0;
|
uint16_t prev_kbit_rate = 0;
|
||||||
|
|
|
@ -6,10 +6,14 @@ if compiler.get_id() == 'gcc'
|
||||||
gtest_compile_args += [
|
gtest_compile_args += [
|
||||||
'-Wno-suggest-attribute=format',
|
'-Wno-suggest-attribute=format',
|
||||||
'-Wno-suggest-attribute=noreturn',
|
'-Wno-suggest-attribute=noreturn',
|
||||||
'-Wno-missing-declarations',
|
]
|
||||||
|
endif
|
||||||
|
|
||||||
# needed on Jessie for gtest's IsNullLiteralHelper
|
if compiler.get_id() == 'clang' and compiler.version().version_compare('>=9')
|
||||||
'-Wno-conversion-null',
|
gtest_compile_args += [
|
||||||
|
# work around clang warning caused by GTest's wrong "-lpthread"
|
||||||
|
# compiler flag
|
||||||
|
'-Wno-unused-command-line-argument',
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -47,16 +47,20 @@ struct CommandLine {
|
||||||
Path config_path = nullptr;
|
Path config_path = nullptr;
|
||||||
|
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
|
|
||||||
|
SongTime seek_where{};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Option {
|
enum Option {
|
||||||
OPTION_CONFIG,
|
OPTION_CONFIG,
|
||||||
OPTION_VERBOSE,
|
OPTION_VERBOSE,
|
||||||
|
OPTION_SEEK,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr OptionDef option_defs[] = {
|
static constexpr OptionDef option_defs[] = {
|
||||||
{"config", 0, true, "Load a MPD configuration file"},
|
{"config", 0, true, "Load a MPD configuration file"},
|
||||||
{"verbose", 'v', false, "Verbose logging"},
|
{"verbose", 'v', false, "Verbose logging"},
|
||||||
|
{"seek", 0, true, "Seek to this position"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static CommandLine
|
static CommandLine
|
||||||
|
@ -74,6 +78,10 @@ ParseCommandLine(int argc, char **argv)
|
||||||
case OPTION_VERBOSE:
|
case OPTION_VERBOSE:
|
||||||
c.verbose = true;
|
c.verbose = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPTION_SEEK:
|
||||||
|
c.seek_where = SongTime::FromS(strtod(o.value, nullptr));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +110,85 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MyDecoderClient final : public DumpDecoderClient {
|
||||||
|
SongTime seek_where;
|
||||||
|
|
||||||
|
unsigned sample_rate;
|
||||||
|
|
||||||
|
bool seekable, seek_error = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MyDecoderClient(SongTime _seek_where) noexcept
|
||||||
|
:seek_where(_seek_where) {}
|
||||||
|
|
||||||
|
void Finish() {
|
||||||
|
if (!IsInitialized())
|
||||||
|
throw "Unrecognized file";
|
||||||
|
|
||||||
|
if (seek_error)
|
||||||
|
throw "Seek error";
|
||||||
|
|
||||||
|
if (seek_where != SongTime{}) {
|
||||||
|
if (!seekable)
|
||||||
|
throw "Not seekable";
|
||||||
|
|
||||||
|
throw "Did not seek";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual methods from DecoderClient */
|
||||||
|
void Ready(AudioFormat audio_format,
|
||||||
|
bool _seekable, SignedSongTime duration) noexcept override {
|
||||||
|
assert(!IsInitialized());
|
||||||
|
|
||||||
|
DumpDecoderClient::Ready(audio_format, _seekable, duration);
|
||||||
|
sample_rate = audio_format.sample_rate;
|
||||||
|
seekable = _seekable;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecoderCommand GetCommand() noexcept override {
|
||||||
|
assert(IsInitialized());
|
||||||
|
|
||||||
|
if (seek_where != SongTime{}) {
|
||||||
|
if (!seekable)
|
||||||
|
return DecoderCommand::STOP;
|
||||||
|
|
||||||
|
return DecoderCommand::SEEK;
|
||||||
|
} else if (seek_error)
|
||||||
|
return DecoderCommand::STOP;
|
||||||
|
else
|
||||||
|
return DumpDecoderClient::GetCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandFinished() noexcept override {
|
||||||
|
assert(!seek_error);
|
||||||
|
|
||||||
|
if (seek_where != SongTime{})
|
||||||
|
seek_where = {};
|
||||||
|
else
|
||||||
|
DumpDecoderClient::CommandFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
SongTime GetSeekTime() noexcept override {
|
||||||
|
assert(seek_where != SongTime{});
|
||||||
|
|
||||||
|
return seek_where;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t GetSeekFrame() noexcept override {
|
||||||
|
assert(seek_where != SongTime{});
|
||||||
|
|
||||||
|
return GetSeekTime().ToScale<uint64_t>(sample_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SeekError() noexcept override {
|
||||||
|
assert(seek_where != SongTime{});
|
||||||
|
|
||||||
|
seek_error = true;
|
||||||
|
seek_where = {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
try {
|
try {
|
||||||
const auto c = ParseCommandLine(argc, argv);
|
const auto c = ParseCommandLine(argc, argv);
|
||||||
|
@ -115,7 +202,7 @@ try {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DumpDecoderClient client;
|
MyDecoderClient client(c.seek_where);
|
||||||
if (plugin->file_decode != nullptr) {
|
if (plugin->file_decode != nullptr) {
|
||||||
try {
|
try {
|
||||||
plugin->FileDecode(client, Path::FromFS(c.uri));
|
plugin->FileDecode(client, Path::FromFS(c.uri));
|
||||||
|
@ -132,10 +219,7 @@ try {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!client.IsInitialized()) {
|
client.Finish();
|
||||||
fprintf(stderr, "Decoding failed\n");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
Loading…
Reference in New Issue