diff --git a/NEWS b/NEWS index 8f3901e00..1e69582bf 100644 --- a/NEWS +++ b/NEWS @@ -35,6 +35,12 @@ ver 0.22 (not yet released) * switch to C++17 - 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) * configuration - allow overriding top-level settings in includes diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 25c755885..a7ea8a550 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="43" + android:versionName="0.21.20"> diff --git a/src/CommandLine.cxx b/src/CommandLine.cxx index 765b621b5..4249b1f2f 100644 --- a/src/CommandLine.cxx +++ b/src/CommandLine.cxx @@ -297,7 +297,7 @@ public: explicit ConfigLoader(ConfigData &_config) noexcept :config(_config) {} - bool TryFile(const Path path); + bool TryFile(Path path); bool TryFile(const AllocatedPath &base_path, Path path); }; diff --git a/src/archive/plugins/ZzipArchivePlugin.cxx b/src/archive/plugins/ZzipArchivePlugin.cxx index bb1776379..db85e0d32 100644 --- a/src/archive/plugins/ZzipArchivePlugin.cxx +++ b/src/archive/plugins/ZzipArchivePlugin.cxx @@ -91,7 +91,7 @@ class ZzipInputStream final : public InputStream { ZZIP_FILE *const file; public: - ZzipInputStream(const std::shared_ptr _dir, const char *_uri, + ZzipInputStream(const std::shared_ptr& _dir, const char *_uri, Mutex &_mutex, ZZIP_FILE *_file) :InputStream(_uri, _mutex), diff --git a/src/command/CommandError.cxx b/src/command/CommandError.cxx index f96932613..1b0c60fab 100644 --- a/src/command/CommandError.cxx +++ b/src/command/CommandError.cxx @@ -82,7 +82,7 @@ ToAck(DatabaseErrorCode code) noexcept gcc_pure static enum ack -ToAck(std::exception_ptr ep) noexcept +ToAck(const std::exception_ptr& ep) noexcept { try { std::rethrow_exception(ep); @@ -113,7 +113,7 @@ ToAck(std::exception_ptr ep) noexcept } void -PrintError(Response &r, std::exception_ptr ep) +PrintError(Response &r, const std::exception_ptr& ep) { LogError(ep); r.Error(ToAck(ep), GetFullMessage(ep).c_str()); diff --git a/src/command/CommandError.hxx b/src/command/CommandError.hxx index 8209135e9..5ca806899 100644 --- a/src/command/CommandError.hxx +++ b/src/command/CommandError.hxx @@ -28,6 +28,6 @@ class Response; * Send the exception to the client. */ void -PrintError(Response &r, std::exception_ptr ep); +PrintError(Response &r, const std::exception_ptr& ep); #endif diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx index 9519045ea..7f3b4f296 100644 --- a/src/command/PlayerCommands.cxx +++ b/src/command/PlayerCommands.cxx @@ -174,7 +174,7 @@ handle_status(Client &client, gcc_unused Request args, Response &r) COMMAND_STATUS_BITRATE ": %u\n", player_status.elapsed_time.RoundS(), player_status.total_time.IsNegative() - ? 0u + ? 0U : unsigned(player_status.total_time.RoundS()), player_status.elapsed_time.ToDoubleS(), player_status.bit_rate); diff --git a/src/config/Data.cxx b/src/config/Data.cxx index 0c84eeebe..479b8fa6b 100644 --- a/src/config/Data.cxx +++ b/src/config/Data.cxx @@ -50,7 +50,7 @@ template static auto Append(std::forward_list &list, T &&src) { - return list.emplace_after(FindLast(list), std::move(src)); + return list.emplace_after(FindLast(list), std::forward(src)); } void diff --git a/src/db/DatabasePlaylist.cxx b/src/db/DatabasePlaylist.cxx index 78a9d9b67..ae4170ffe 100644 --- a/src/db/DatabasePlaylist.cxx +++ b/src/db/DatabasePlaylist.cxx @@ -39,7 +39,6 @@ search_add_to_playlist(const Database &db, const Storage *storage, const DatabaseSelection &selection) { using namespace std::placeholders; - const auto f = std::bind(AddSong, storage, - playlist_path_utf8, _1); + const auto f = [=](auto && arg1) { return AddSong(storage, playlist_path_utf8, arg1); }; db.Visit(selection, f); } diff --git a/src/db/plugins/ProxyDatabasePlugin.cxx b/src/db/plugins/ProxyDatabasePlugin.cxx index c393fea72..74ce9e8d1 100644 --- a/src/db/plugins/ProxyDatabasePlugin.cxx +++ b/src/db/plugins/ProxyDatabasePlugin.cxx @@ -50,8 +50,9 @@ #include #include -#include #include +#include +#include class LibmpdclientError final : public std::runtime_error { enum mpd_error code; @@ -447,7 +448,7 @@ ProxyDatabase::ProxyDatabase(EventLoop &_loop, DatabaseListener &_listener, listener(_listener), host(block.GetBlockValue("host", "")), password(block.GetBlockValue("password", "")), - port(block.GetBlockValue("port", 0u)), + port(block.GetBlockValue("port", 0U)), keepalive(block.GetBlockValue("keepalive", false)) { } @@ -516,7 +517,7 @@ ProxyDatabase::Connect() (void)keepalive; #endif - idle_received = ~0u; + idle_received = ~0U; is_idle = false; 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 Visit(struct mpd_connection *connection, const char *uri, bool recursive, const SongFilter *filter, - VisitDirectory visit_directory, VisitSong visit_song, - VisitPlaylist visit_playlist); + const VisitDirectory& visit_directory, const VisitSong& visit_song, + const VisitPlaylist& visit_playlist); static void Visit(struct mpd_connection *connection, bool recursive, const SongFilter *filter, const struct mpd_directory *directory, - VisitDirectory visit_directory, VisitSong visit_song, - VisitPlaylist visit_playlist) + const VisitDirectory& visit_directory, const VisitSong& visit_song, + const VisitPlaylist& visit_playlist) { const char *path = mpd_directory_get_path(directory); @@ -697,7 +698,7 @@ Visit(struct mpd_connection *connection, if (recursive) Visit(connection, path, recursive, filter, - visit_directory, visit_song, visit_playlist); + visit_directory, std::move(visit_song), std::move(visit_playlist)); } gcc_pure @@ -710,7 +711,7 @@ Match(const SongFilter *filter, const LightSong &song) noexcept static void Visit(const SongFilter *filter, const mpd_song *_song, - VisitSong visit_song) + const VisitSong& visit_song) { if (!visit_song) return; @@ -722,7 +723,7 @@ Visit(const SongFilter *filter, static void Visit(const struct mpd_playlist *playlist, - VisitPlaylist visit_playlist) + const VisitPlaylist& visit_playlist) { if (!visit_playlist) return; @@ -778,8 +779,8 @@ ReceiveEntities(struct mpd_connection *connection) noexcept static void Visit(struct mpd_connection *connection, const char *uri, bool recursive, const SongFilter *filter, - VisitDirectory visit_directory, VisitSong visit_song, - VisitPlaylist visit_playlist) + const VisitDirectory& visit_directory, const VisitSong& visit_song, + const VisitPlaylist& visit_playlist) { if (!mpd_send_list_meta(connection, uri)) ThrowError(connection); @@ -813,7 +814,7 @@ Visit(struct mpd_connection *connection, const char *uri, static void SearchSongs(struct mpd_connection *connection, const DatabaseSelection &selection, - VisitSong visit_song) + const VisitSong& visit_song) try { assert(selection.recursive); assert(visit_song); diff --git a/src/db/plugins/simple/Directory.cxx b/src/db/plugins/simple/Directory.cxx index e478b6d06..e372c3685 100644 --- a/src/db/plugins/simple/Directory.cxx +++ b/src/db/plugins/simple/Directory.cxx @@ -220,8 +220,8 @@ Directory::Sort() noexcept void Directory::Walk(bool recursive, const SongFilter *filter, - VisitDirectory visit_directory, VisitSong visit_song, - VisitPlaylist visit_playlist) const + const VisitDirectory& visit_directory, const VisitSong& visit_song, + const VisitPlaylist& visit_playlist) const { if (IsMount()) { assert(IsEmpty()); diff --git a/src/db/plugins/simple/Directory.hxx b/src/db/plugins/simple/Directory.hxx index 26069ec99..33d08d804 100644 --- a/src/db/plugins/simple/Directory.hxx +++ b/src/db/plugins/simple/Directory.hxx @@ -284,8 +284,8 @@ public: * Caller must lock #db_mutex. */ void Walk(bool recursive, const SongFilter *match, - VisitDirectory visit_directory, VisitSong visit_song, - VisitPlaylist visit_playlist) const; + const VisitDirectory& visit_directory, const VisitSong& visit_song, + const VisitPlaylist& visit_playlist) const; gcc_pure LightDirectory Export() const noexcept; diff --git a/src/db/plugins/upnp/UpnpDatabasePlugin.cxx b/src/db/plugins/upnp/UpnpDatabasePlugin.cxx index 6145d535e..8b1dc0213 100644 --- a/src/db/plugins/upnp/UpnpDatabasePlugin.cxx +++ b/src/db/plugins/upnp/UpnpDatabasePlugin.cxx @@ -41,6 +41,7 @@ #include "util/SplitString.hxx" #include +#include #include #include @@ -107,9 +108,9 @@ private: void VisitServer(const ContentDirectoryService &server, std::forward_list &&vpath, const DatabaseSelection &selection, - VisitDirectory visit_directory, - VisitSong visit_song, - VisitPlaylist visit_playlist) const; + const VisitDirectory& visit_directory, + const VisitSong& visit_song, + const VisitPlaylist& visit_playlist) const; /** * Run an UPnP search according to MPD parameters, and @@ -118,7 +119,7 @@ private: void SearchSongs(const ContentDirectoryService &server, const char *objid, const DatabaseSelection &selection, - VisitSong visit_song) const; + const VisitSong& visit_song) const; UPnPDirContent SearchSongs(const ContentDirectoryService &server, const char *objid, @@ -311,7 +312,7 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server, static void visitSong(const UPnPDirObject &meta, const char *path, const DatabaseSelection &selection, - VisitSong visit_song) + const VisitSong& visit_song) { if (!visit_song) return; @@ -339,7 +340,7 @@ void UpnpDatabase::SearchSongs(const ContentDirectoryService &server, const char *objid, const DatabaseSelection &selection, - VisitSong visit_song) const + const VisitSong& visit_song) const { if (!visit_song) return; @@ -440,13 +441,13 @@ UpnpDatabase::Namei(const ContentDirectoryService &server, static void VisitItem(const UPnPDirObject &object, const char *uri, const DatabaseSelection &selection, - VisitSong visit_song, VisitPlaylist visit_playlist) + const VisitSong& visit_song, const VisitPlaylist& visit_playlist) { assert(object.type == UPnPDirObject::Type::ITEM); switch (object.item_class) { case UPnPDirObject::ItemClass::MUSIC: - visitSong(object, uri, selection, visit_song); + visitSong(object, uri, selection, std::move(visit_song)); break; case UPnPDirObject::ItemClass::PLAYLIST: @@ -469,9 +470,9 @@ VisitItem(const UPnPDirObject &object, const char *uri, static void VisitObject(const UPnPDirObject &object, const char *uri, const DatabaseSelection &selection, - VisitDirectory visit_directory, - VisitSong visit_song, - VisitPlaylist visit_playlist) + const VisitDirectory& visit_directory, + const VisitSong& visit_song, + const VisitPlaylist& visit_playlist) { switch (object.type) { case UPnPDirObject::Type::UNKNOWN: @@ -486,7 +487,7 @@ VisitObject(const UPnPDirObject &object, const char *uri, case UPnPDirObject::Type::ITEM: VisitItem(object, uri, selection, - visit_song, visit_playlist); + std::move(visit_song), std::move(visit_playlist)); break; } } @@ -497,9 +498,9 @@ void UpnpDatabase::VisitServer(const ContentDirectoryService &server, std::forward_list &&vpath, const DatabaseSelection &selection, - VisitDirectory visit_directory, - VisitSong visit_song, - VisitPlaylist visit_playlist) const + const VisitDirectory& visit_directory, + const VisitSong& visit_song, + const VisitPlaylist& visit_playlist) const { /* If the path begins with rootid, we know that this is a song, not a directory (because that's how we set things diff --git a/src/decoder/plugins/AdPlugDecoderPlugin.cxx b/src/decoder/plugins/AdPlugDecoderPlugin.cxx index 6636cd910..a64946bfd 100644 --- a/src/decoder/plugins/AdPlugDecoderPlugin.cxx +++ b/src/decoder/plugins/AdPlugDecoderPlugin.cxx @@ -41,7 +41,7 @@ adplug_init(const ConfigBlock &block) FormatDebug(adplug_domain, "adplug %s", CAdPlug::get_version().c_str()); - sample_rate = block.GetPositiveValue("sample_rate", 48000u); + sample_rate = block.GetPositiveValue("sample_rate", 48000U); CheckSampleRate(sample_rate); return true; diff --git a/src/decoder/plugins/AudiofileDecoderPlugin.cxx b/src/decoder/plugins/AudiofileDecoderPlugin.cxx index 63ecff3ca..527f7d41f 100644 --- a/src/decoder/plugins/AudiofileDecoderPlugin.cxx +++ b/src/decoder/plugins/AudiofileDecoderPlugin.cxx @@ -200,7 +200,7 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is) AudioFileInputStream afis{&client, is}; 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) return; @@ -269,6 +269,8 @@ static const char *const audiofile_suffixes[] = { }; static const char *const audiofile_mime_types[] = { + "audio/wav", + "audio/aiff", "audio/x-wav", "audio/x-aiff", nullptr diff --git a/src/decoder/plugins/DsdLib.cxx b/src/decoder/plugins/DsdLib.cxx index d19de96a1..042571b9e 100644 --- a/src/decoder/plugins/DsdLib.cxx +++ b/src/decoder/plugins/DsdLib.cxx @@ -150,6 +150,5 @@ dsdlib_tag_id3(InputStream &is, TagHandler &handler, scan_id3_tag(id3_tag, handler); id3_tag_delete(id3_tag); - return; } #endif diff --git a/src/decoder/plugins/DsdiffDecoderPlugin.cxx b/src/decoder/plugins/DsdiffDecoderPlugin.cxx index ef98f32f3..ba6a78079 100644 --- a/src/decoder/plugins/DsdiffDecoderPlugin.cxx +++ b/src/decoder/plugins/DsdiffDecoderPlugin.cxx @@ -213,7 +213,6 @@ dsdiff_handle_native_tag(DecoderClient *client, InputStream &is, return; handler.OnTag(type, {label, length}); - return; } /** diff --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx index c56ae7608..983103e0e 100644 --- a/src/decoder/plugins/FaadDecoderPlugin.cxx +++ b/src/decoder/plugins/FaadDecoderPlugin.cxx @@ -231,7 +231,7 @@ faad_song_duration(DecoderBuffer &buffer, InputStream &is) static NeAACDecHandle faad_decoder_new() { - const NeAACDecHandle decoder = NeAACDecOpen(); + auto decoder = NeAACDecOpen(); NeAACDecConfigurationPtr config = NeAACDecGetCurrentConfiguration(decoder); @@ -324,7 +324,7 @@ faad_get_file_time(InputStream &is) static void 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); @@ -406,7 +406,7 @@ faad_stream_decode(DecoderClient &client, InputStream &is) /* create the libfaad decoder */ - const NeAACDecHandle decoder = faad_decoder_new(); + auto decoder = faad_decoder_new(); AtScopeExit(decoder) { NeAACDecClose(decoder); }; faad_stream_decode(client, is, buffer, decoder); diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx index 6be0448b9..58795e3ea 100644 --- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx +++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx @@ -698,7 +698,7 @@ static const char *const ffmpeg_mime_types[] = { "audio/aac", "audio/aacp", "audio/ac3", - "audio/aiff" + "audio/aiff", "audio/amr", "audio/basic", "audio/flac", @@ -711,12 +711,13 @@ static const char *const ffmpeg_mime_types[] = { "audio/qcelp", "audio/vorbis", "audio/vorbis+ogg", + "audio/wav", "audio/x-8svx", "audio/x-16sv", "audio/x-aac", "audio/x-ac3", "audio/x-adx", - "audio/x-aiff" + "audio/x-aiff", "audio/x-alaw", "audio/x-au", "audio/x-dca", @@ -736,7 +737,7 @@ static const char *const ffmpeg_mime_types[] = { "audio/x-pn-realaudio", "audio/x-pn-multirate-realaudio", "audio/x-speex", - "audio/x-tta" + "audio/x-tta", "audio/x-voc", "audio/x-wav", "audio/x-wma", diff --git a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx index b5de380ae..722aa44d0 100644 --- a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx +++ b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx @@ -77,7 +77,7 @@ fluidsynth_mpd_log_function(int level, static bool fluidsynth_init(const ConfigBlock &block) { - sample_rate = block.GetPositiveValue("sample_rate", 48000u); + sample_rate = block.GetPositiveValue("sample_rate", 48000U); CheckSampleRate(sample_rate); soundfont_path = block.GetBlockValue("soundfont", diff --git a/src/decoder/plugins/HybridDsdDecoderPlugin.cxx b/src/decoder/plugins/HybridDsdDecoderPlugin.cxx index 87f718c57..2eece030d 100644 --- a/src/decoder/plugins/HybridDsdDecoderPlugin.cxx +++ b/src/decoder/plugins/HybridDsdDecoderPlugin.cxx @@ -186,7 +186,7 @@ HybridDsdDecode(DecoderClient &client, InputStream &input) client.Ready(result.first, true, duration); frame_size = result.first.GetFrameSize(); kbit_rate = frame_size * result.first.sample_rate / - (1024u / 8u); + (1024U / 8U); total_frames = result.second / frame_size; } catch (UnsupportedFile) { /* not a Hybrid-DSD file; let the next decoder plugin @@ -236,7 +236,7 @@ HybridDsdDecode(DecoderClient &client, InputStream &input) /* fill the buffer */ auto w = buffer.Write(); if (!w.empty()) { - if (remaining_bytes < (1<<30ull) && + if (remaining_bytes < (1<<30ULL) && w.size > size_t(remaining_bytes)) w.size = remaining_bytes; diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx index e72841155..18b937aac 100644 --- a/src/decoder/plugins/MadDecoderPlugin.cxx +++ b/src/decoder/plugins/MadDecoderPlugin.cxx @@ -760,7 +760,7 @@ MadDecoder::DecodeFirstFrame(Tag *tag) noexcept if (max_frames > 8 * 1024 * 1024) { FormatWarning(mad_domain, - "mp3 file header indicates too many frames: %lu", + "mp3 file header indicates too many frames: %zu", max_frames); return false; } diff --git a/src/decoder/plugins/MikmodDecoderPlugin.cxx b/src/decoder/plugins/MikmodDecoderPlugin.cxx index e365adf69..ad6ff51c4 100644 --- a/src/decoder/plugins/MikmodDecoderPlugin.cxx +++ b/src/decoder/plugins/MikmodDecoderPlugin.cxx @@ -108,7 +108,7 @@ mikmod_decoder_init(const ConfigBlock &block) static char params[] = ""; 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)) throw FormatRuntimeError("Invalid sample rate in line %d: %u", block.line, mikmod_sample_rate); diff --git a/src/decoder/plugins/OggDecoder.cxx b/src/decoder/plugins/OggDecoder.cxx index 10f935743..da9bad2b9 100644 --- a/src/decoder/plugins/OggDecoder.cxx +++ b/src/decoder/plugins/OggDecoder.cxx @@ -45,8 +45,12 @@ OggDecoder::LoadEndPacket(ogg_packet &packet) const DecoderReader reader(client, input_stream); OggSyncState sync2(reader); 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, - input_stream); + input_stream, false); } /* restore the previous file position */ diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx index 253a3f317..d71e9bd63 100644 --- a/src/decoder/plugins/SidplayDecoderPlugin.cxx +++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx @@ -127,7 +127,7 @@ SidplayGlobal::SidplayGlobal(const ConfigBlock &block) if (!database_path.IsNull()) 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", ""); @@ -403,7 +403,7 @@ sidplay_file_decode(DecoderClient &client, Path path_fs) const unsigned timebase = player.timebase(); #endif const unsigned end = duration.IsNegative() - ? 0u + ? 0U : duration.ToScale(timebase); DecoderCommand cmd; diff --git a/src/decoder/plugins/SndfileDecoderPlugin.cxx b/src/decoder/plugins/SndfileDecoderPlugin.cxx index 412ec2dfc..91baf1275 100644 --- a/src/decoder/plugins/SndfileDecoderPlugin.cxx +++ b/src/decoder/plugins/SndfileDecoderPlugin.cxx @@ -323,6 +323,8 @@ static const char *const sndfile_suffixes[] = { }; static const char *const sndfile_mime_types[] = { + "audio/wav", + "audio/aiff", "audio/x-wav", "audio/x-aiff", diff --git a/src/encoder/plugins/FlacEncoderPlugin.cxx b/src/encoder/plugins/FlacEncoderPlugin.cxx index a433b6188..02e249220 100644 --- a/src/encoder/plugins/FlacEncoderPlugin.cxx +++ b/src/encoder/plugins/FlacEncoderPlugin.cxx @@ -93,7 +93,7 @@ public: }; PreparedFlacEncoder::PreparedFlacEncoder(const ConfigBlock &block) - :compression(block.GetBlockValue("compression", 5u)) + :compression(block.GetBlockValue("compression", 5U)) { } diff --git a/src/encoder/plugins/OpusEncoderPlugin.cxx b/src/encoder/plugins/OpusEncoderPlugin.cxx index c445feeba..ae693ea33 100644 --- a/src/encoder/plugins/OpusEncoderPlugin.cxx +++ b/src/encoder/plugins/OpusEncoderPlugin.cxx @@ -105,7 +105,7 @@ PreparedOpusEncoder::PreparedOpusEncoder(const ConfigBlock &block) throw std::runtime_error("Invalid bit rate"); } - complexity = block.GetBlockValue("complexity", 10u); + complexity = block.GetBlockValue("complexity", 10U); if (complexity > 10) throw std::runtime_error("Invalid complexity"); diff --git a/src/input/Error.cxx b/src/input/Error.cxx index 80e21c31a..b6d34091d 100644 --- a/src/input/Error.cxx +++ b/src/input/Error.cxx @@ -30,11 +30,13 @@ #include #endif +#include + bool IsFileNotFound(std::exception_ptr ep) noexcept { try { - std::rethrow_exception(ep); + std::rethrow_exception(std::move(ep)); } catch (const std::system_error &e) { return IsFileNotFound(e); #ifdef ENABLE_CURL diff --git a/src/input/plugins/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx index 4d1903571..9c5f4455e 100644 --- a/src/input/plugins/CdioParanoiaInputPlugin.cxx +++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx @@ -112,7 +112,7 @@ input_cdio_init(EventLoop &, const ConfigBlock &block) throw FormatRuntimeError("Unrecognized 'default_byte_order' setting: %s", value); } - speed = block.GetBlockValue("speed",0u); + speed = block.GetBlockValue("speed",0U); } struct CdioUri { diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 0432e3ee5..2628c2efa 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -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"); 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_password = block.GetBlockValue("proxy_password"); @@ -409,9 +409,9 @@ CurlInputStream::InitEasy() request = new CurlRequest(**curl_init, GetURI(), *this); request->SetOption(CURLOPT_HTTP200ALIASES, http_200_aliases); - request->SetOption(CURLOPT_FOLLOWLOCATION, 1l); - request->SetOption(CURLOPT_MAXREDIRS, 5l); - request->SetOption(CURLOPT_FAILONERROR, 1l); + request->SetOption(CURLOPT_FOLLOWLOCATION, 1L); + request->SetOption(CURLOPT_MAXREDIRS, 5L); + request->SetOption(CURLOPT_FAILONERROR, 1L); if (proxy != nullptr) request->SetOption(CURLOPT_PROXY, proxy); @@ -424,8 +424,8 @@ CurlInputStream::InitEasy() StringFormat<1024>("%s:%s", proxy_user, proxy_password).c_str()); - request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1l : 0l); - request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l); + request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1L : 0L); + request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2L : 0L); request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get()); } diff --git a/src/input/plugins/QobuzInputPlugin.cxx b/src/input/plugins/QobuzInputPlugin.cxx index 85b31a1c0..3936cb371 100644 --- a/src/input/plugins/QobuzInputPlugin.cxx +++ b/src/input/plugins/QobuzInputPlugin.cxx @@ -65,7 +65,7 @@ public: } private: - void Failed(std::exception_ptr e) { + void Failed(const std::exception_ptr& e) { SetInput(std::make_unique(GetURI(), e, mutex)); } diff --git a/src/input/plugins/TidalInputPlugin.cxx b/src/input/plugins/TidalInputPlugin.cxx index 6df562047..b0c3bf9dc 100644 --- a/src/input/plugins/TidalInputPlugin.cxx +++ b/src/input/plugins/TidalInputPlugin.cxx @@ -35,6 +35,7 @@ #include "Log.hxx" #include +#include static constexpr Domain tidal_domain("tidal"); @@ -77,7 +78,7 @@ public: } private: - void Failed(std::exception_ptr e) { + void Failed(const std::exception_ptr& e) { SetInput(std::make_unique(GetURI(), e, mutex)); } @@ -133,7 +134,7 @@ static bool IsInvalidSession(std::exception_ptr e) noexcept { try { - std::rethrow_exception(e); + std::rethrow_exception(std::move(e)); } catch (const TidalError &te) { return te.IsInvalidSession(); } catch (...) { diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx index 9126ee5c7..864a92d3f 100644 --- a/src/lib/curl/Request.cxx +++ b/src/lib/curl/Request.cxx @@ -56,7 +56,7 @@ CurlRequest::CurlRequest(CurlGlobal &_global, easy.SetUserAgent("Music Player Daemon " VERSION); easy.SetHeaderFunction(_HeaderFunction, this); easy.SetWriteFunction(WriteFunction, this); - easy.SetOption(CURLOPT_NETRC, 1l); + easy.SetOption(CURLOPT_NETRC, 1L); easy.SetErrorBuffer(error_buffer); easy.SetNoProgress(); easy.SetNoSignal(); diff --git a/src/lib/dbus/UDisks2.cxx b/src/lib/dbus/UDisks2.cxx index d07e5aabe..0b1fefd94 100644 --- a/src/lib/dbus/UDisks2.cxx +++ b/src/lib/dbus/UDisks2.cxx @@ -167,7 +167,7 @@ ParseObjects(ODBus::ReadMessageIter &&i, ForEachInterface(std::move(i), [&callback](const char *path, auto &&j){ Object o(path); - ParseObject(o, std::move(j)); + ParseObject(o, std::forward(j)); if (o.IsValid()) callback(std::move(o)); }); diff --git a/src/lib/icu/CaseFold.cxx b/src/lib/icu/CaseFold.cxx index 120f87893..74e378e92 100644 --- a/src/lib/icu/CaseFold.cxx +++ b/src/lib/icu/CaseFold.cxx @@ -58,7 +58,7 @@ try { if (u.IsNull()) return AllocatedString<>::Duplicate(src); - AllocatedArray folded(u.size() * 2u); + AllocatedArray folded(u.size() * 2U); UErrorCode error_code = U_ZERO_ERROR; size_t folded_length = u_strFoldCase(folded.begin(), folded.size(), diff --git a/src/lib/upnp/ContentDirectoryService.cxx b/src/lib/upnp/ContentDirectoryService.cxx index f43a304a9..539da0fa5 100644 --- a/src/lib/upnp/ContentDirectoryService.cxx +++ b/src/lib/upnp/ContentDirectoryService.cxx @@ -37,7 +37,7 @@ ContentDirectoryService::ContentDirectoryService(const UPnPDevice &device, m_modelName(device.modelName), m_rdreqcnt(200) { - if (!m_modelName.compare("MediaTomb")) { + if (m_modelName == "MediaTomb") { // Readdir by 200 entries is good for most, but MediaTomb likes // them really big. Actually 1000 is better but I don't dare m_rdreqcnt = 500; diff --git a/src/lib/xiph/OggFind.cxx b/src/lib/xiph/OggFind.cxx index 88ed42cc5..bd6299df5 100644 --- a/src/lib/xiph/OggFind.cxx +++ b/src/lib/xiph/OggFind.cxx @@ -57,13 +57,14 @@ OggSeekPageAtOffset(OggSyncState &oy, ogg_stream_state &os, InputStream &is, bool OggSeekFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet, - InputStream &is) + InputStream &is, bool synced) { if (!is.KnownSize()) return false; if (is.GetRest() < 65536) - return OggFindEOS(oy, os, packet); + return (synced || oy.ExpectPageSeekIn(os)) && + OggFindEOS(oy, os, packet); if (!is.CheapSeeking()) return false; diff --git a/src/lib/xiph/OggFind.hxx b/src/lib/xiph/OggFind.hxx index d04b0b3b3..f2050118d 100644 --- a/src/lib/xiph/OggFind.hxx +++ b/src/lib/xiph/OggFind.hxx @@ -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 * 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 */ bool OggSeekFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet, - InputStream &is); + InputStream &is, bool synced=true); #endif diff --git a/src/lib/xiph/OggSyncState.cxx b/src/lib/xiph/OggSyncState.cxx index f8d7aa67c..adbeb4461 100644 --- a/src/lib/xiph/OggSyncState.cxx +++ b/src/lib/xiph/OggSyncState.cxx @@ -43,7 +43,7 @@ OggSyncState::ExpectPage(ogg_page &page) if (r != 0) { if (r > 0) { start_offset = offset; - offset += r; + offset += page.header_len + page.body_len; } return r > 0; } diff --git a/src/neighbor/plugins/UdisksNeighborPlugin.cxx b/src/neighbor/plugins/UdisksNeighborPlugin.cxx index 9206048ed..820271d67 100644 --- a/src/neighbor/plugins/UdisksNeighborPlugin.cxx +++ b/src/neighbor/plugins/UdisksNeighborPlugin.cxx @@ -231,7 +231,7 @@ UdisksNeighborExplorer::HandleMessage(DBusConnection *, DBusMessage *message) no dbus_message_has_signature(message, InterfacesAddedType::value)) { RecurseInterfaceDictEntry(ReadMessageIter(*message), [this](const char *path, auto &&i){ UDisks2::Object o(path); - UDisks2::ParseObject(o, std::move(i)); + UDisks2::ParseObject(o, std::forward(i)); if (o.IsValid()) this->Insert(std::move(o)); }); diff --git a/src/output/Control.cxx b/src/output/Control.cxx index b41acbb7c..d6b100ff1 100644 --- a/src/output/Control.cxx +++ b/src/output/Control.cxx @@ -116,7 +116,7 @@ AudioOutputControl::GetMixer() const noexcept return output ? output->mixer : nullptr; } -const std::map +std::map AudioOutputControl::GetAttributes() const noexcept { return output diff --git a/src/output/Control.hxx b/src/output/Control.hxx index ef9cf5f2b..5a254a7ae 100644 --- a/src/output/Control.hxx +++ b/src/output/Control.hxx @@ -357,7 +357,7 @@ public: void BeginDestroy() noexcept; - const std::map GetAttributes() const noexcept; + std::map GetAttributes() const noexcept; void SetAttribute(std::string &&name, std::string &&value); /** diff --git a/src/output/Filtered.cxx b/src/output/Filtered.cxx index 462ce2fdb..45c957141 100644 --- a/src/output/Filtered.cxx +++ b/src/output/Filtered.cxx @@ -39,7 +39,7 @@ FilteredAudioOutput::SupportsPause() const noexcept return output->SupportsPause(); } -const std::map +std::map FilteredAudioOutput::GetAttributes() const noexcept { return output->GetAttributes(); diff --git a/src/output/Filtered.hxx b/src/output/Filtered.hxx index ca527e26e..97d37765a 100644 --- a/src/output/Filtered.hxx +++ b/src/output/Filtered.hxx @@ -170,7 +170,7 @@ public: gcc_pure bool SupportsPause() const noexcept; - const std::map GetAttributes() const noexcept; + std::map GetAttributes() const noexcept; void SetAttribute(std::string &&name, std::string &&value); /** diff --git a/src/output/Interface.hxx b/src/output/Interface.hxx index 99d63360e..63ee4668f 100644 --- a/src/output/Interface.hxx +++ b/src/output/Interface.hxx @@ -64,7 +64,7 @@ public: * * This method must be thread-safe. */ - virtual const std::map GetAttributes() const noexcept { + virtual std::map GetAttributes() const noexcept { return {}; } diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx index 504090a88..1aefbbe7d 100644 --- a/src/output/plugins/AlsaOutputPlugin.cxx +++ b/src/output/plugins/AlsaOutputPlugin.cxx @@ -228,7 +228,7 @@ public: } private: - const std::map GetAttributes() const noexcept override; + std::map GetAttributes() const noexcept override; void SetAttribute(std::string &&name, std::string &&value) override; void Enable() override; @@ -404,7 +404,7 @@ AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block) #endif buffer_time(block.GetPositiveValue("buffer_time", 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 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); } -const std::map +std::map AlsaOutput::GetAttributes() const noexcept { const std::lock_guard lock(attributes_mutex); diff --git a/src/output/plugins/AoOutputPlugin.cxx b/src/output/plugins/AoOutputPlugin.cxx index ec700d607..f6561be2c 100644 --- a/src/output/plugins/AoOutputPlugin.cxx +++ b/src/output/plugins/AoOutputPlugin.cxx @@ -101,7 +101,7 @@ MakeAoError() AoOutput::AoOutput(const ConfigBlock &block) :AudioOutput(0), - write_size(block.GetPositiveValue("write_size", 1024u)) + write_size(block.GetPositiveValue("write_size", 1024U)) { const char *value = block.GetBlockValue("driver", "default"); if (StringIsEqual(value, "default")) diff --git a/src/output/plugins/JackOutputPlugin.cxx b/src/output/plugins/JackOutputPlugin.cxx index 4ce6a7a5e..165d4651d 100644 --- a/src/output/plugins/JackOutputPlugin.cxx +++ b/src/output/plugins/JackOutputPlugin.cxx @@ -247,7 +247,7 @@ JackOutput::JackOutput(const ConfigBlock &block) num_source_ports, num_destination_ports, block.line); - ringbuffer_size = block.GetPositiveValue("ringbuffer_size", 32768u); + ringbuffer_size = block.GetPositiveValue("ringbuffer_size", 32768U); } inline jack_nframes_t diff --git a/src/output/plugins/ShoutOutputPlugin.cxx b/src/output/plugins/ShoutOutputPlugin.cxx index 7f7a49b5e..36f8bb8c9 100644 --- a/src/output/plugins/ShoutOutputPlugin.cxx +++ b/src/output/plugins/ShoutOutputPlugin.cxx @@ -99,7 +99,7 @@ ShoutOutput::ShoutOutput(const ConfigBlock &block) { const char *host = require_block_string(block, "host"); const char *mount = require_block_string(block, "mount"); - unsigned port = block.GetBlockValue("port", 0u); + unsigned port = block.GetBlockValue("port", 0U); if (port == 0) throw std::runtime_error("shout port must be configured"); diff --git a/src/output/plugins/httpd/HttpdOutputPlugin.cxx b/src/output/plugins/httpd/HttpdOutputPlugin.cxx index 349c99eb9..252696b2a 100644 --- a/src/output/plugins/httpd/HttpdOutputPlugin.cxx +++ b/src/output/plugins/httpd/HttpdOutputPlugin.cxx @@ -50,11 +50,11 @@ HttpdOutput::HttpdOutput(EventLoop &_loop, const ConfigBlock &block) genre = block.GetBlockValue("genre", "Set genre 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 */ - 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 */ content_type = prepared_encoder->GetMimeType(); diff --git a/src/pcm/Dop.cxx b/src/pcm/Dop.cxx index ed84e4abe..89c68d689 100644 --- a/src/pcm/Dop.cxx +++ b/src/pcm/Dop.cxx @@ -94,5 +94,5 @@ DsdToDopConverter::Convert(ConstBuffer src) noexcept { using namespace std::placeholders; return rest_buffer.Process(buffer, src, 2 * channels, - std::bind(DsdToDop, _1, _2, _3, channels)); + [=](auto && arg1, auto && arg2, auto && arg3) { return DsdToDop(arg1, arg2, arg3, channels); }); } diff --git a/src/pcm/Dsd16.cxx b/src/pcm/Dsd16.cxx index 52cef4bed..24be94570 100644 --- a/src/pcm/Dsd16.cxx +++ b/src/pcm/Dsd16.cxx @@ -65,5 +65,5 @@ Dsd16Converter::Convert(ConstBuffer src) noexcept { using namespace std::placeholders; return rest_buffer.Process(buffer, src, channels, - std::bind(Dsd8To16, _1, _2, _3, channels)); + [=](auto && arg1, auto && arg2, auto && arg3) { return Dsd8To16(arg1, arg2, arg3, channels); }); } diff --git a/src/pcm/Dsd32.cxx b/src/pcm/Dsd32.cxx index a6fd81018..81d94917c 100644 --- a/src/pcm/Dsd32.cxx +++ b/src/pcm/Dsd32.cxx @@ -67,5 +67,5 @@ Dsd32Converter::Convert(ConstBuffer src) noexcept { using namespace std::placeholders; return rest_buffer.Process(buffer, src, channels, - std::bind(Dsd8To32, _1, _2, _3, channels)); + [=](auto && arg1, auto && arg2, auto && arg3) { return Dsd8To32(arg1, arg2, arg3, channels); }); } diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index 64cf16002..4c44d3faa 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -261,8 +261,8 @@ public: CommonExpatParser(ExpatNamespaceSeparator{'|'}) { request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND"); - request.SetOption(CURLOPT_FOLLOWLOCATION, 1l); - request.SetOption(CURLOPT_MAXREDIRS, 1l); + request.SetOption(CURLOPT_FOLLOWLOCATION, 1L); + request.SetOption(CURLOPT_MAXREDIRS, 1L); request_headers.Append(StringFormat<40>("depth: %u", depth)); diff --git a/src/tag/ApeLoader.cxx b/src/tag/ApeLoader.cxx index dcf9dba35..19f881666 100644 --- a/src/tag/ApeLoader.cxx +++ b/src/tag/ApeLoader.cxx @@ -38,7 +38,7 @@ struct ApeFooter { }; bool -tag_ape_scan(InputStream &is, ApeTagCallback callback) +tag_ape_scan(InputStream &is, const ApeTagCallback& callback) try { std::unique_lock lock(is.mutex); diff --git a/src/tag/ApeLoader.hxx b/src/tag/ApeLoader.hxx index 76f34e43b..e930cb3a8 100644 --- a/src/tag/ApeLoader.hxx +++ b/src/tag/ApeLoader.hxx @@ -37,6 +37,6 @@ typedef std::function -struct CheckSequenceUTF8<0u> { +struct CheckSequenceUTF8<0U> { constexpr bool operator()(gcc_unused const char *p) const noexcept { return true; } @@ -217,7 +217,7 @@ InnerSequenceLengthUTF8(const char *p) noexcept { return CheckSequenceUTF8()(p) ? L + 1 - : 0u; + : 0U; } size_t diff --git a/test/DumpDecoderClient.cxx b/test/DumpDecoderClient.cxx index c71d27717..75a8c44e3 100644 --- a/test/DumpDecoderClient.cxx +++ b/test/DumpDecoderClient.cxx @@ -28,15 +28,15 @@ void DumpDecoderClient::Ready(const AudioFormat audio_format, - gcc_unused bool seekable, + bool seekable, SignedSongTime duration) noexcept { assert(!initialized); 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(), - duration.ToDoubleS()); + duration.ToDoubleS(), seekable); initialized = true; } @@ -101,7 +101,7 @@ DumpDecoderClient::SubmitData(gcc_unused InputStream *is, } gcc_unused ssize_t nbytes = write(STDOUT_FILENO, data, datalen); - return DecoderCommand::NONE; + return GetCommand(); } DecoderCommand @@ -113,7 +113,7 @@ DumpDecoderClient::SubmitTag(gcc_unused InputStream *is, for (const auto &i : tag) fprintf(stderr, " %s=%s\n", tag_item_names[i.type], i.value); - return DecoderCommand::NONE; + return GetCommand(); } static void diff --git a/test/DumpDecoderClient.hxx b/test/DumpDecoderClient.hxx index 053b4780c..5bba313c6 100644 --- a/test/DumpDecoderClient.hxx +++ b/test/DumpDecoderClient.hxx @@ -27,7 +27,7 @@ * A #DecoderClient implementation which dumps metadata to stderr and * decoded data to stdout. */ -class DumpDecoderClient final : public DecoderClient { +class DumpDecoderClient : public DecoderClient { bool initialized = false; uint16_t prev_kbit_rate = 0; diff --git a/test/meson.build b/test/meson.build index 7fcf4c822..71dacd67c 100644 --- a/test/meson.build +++ b/test/meson.build @@ -6,10 +6,14 @@ if compiler.get_id() == 'gcc' gtest_compile_args += [ '-Wno-suggest-attribute=format', '-Wno-suggest-attribute=noreturn', - '-Wno-missing-declarations', + ] +endif - # needed on Jessie for gtest's IsNullLiteralHelper - '-Wno-conversion-null', +if compiler.get_id() == 'clang' and compiler.version().version_compare('>=9') + gtest_compile_args += [ + # work around clang warning caused by GTest's wrong "-lpthread" + # compiler flag + '-Wno-unused-command-line-argument', ] endif diff --git a/test/run_decoder.cxx b/test/run_decoder.cxx index 43c8ee4b3..0a31fe28b 100644 --- a/test/run_decoder.cxx +++ b/test/run_decoder.cxx @@ -47,16 +47,20 @@ struct CommandLine { Path config_path = nullptr; bool verbose = false; + + SongTime seek_where{}; }; enum Option { OPTION_CONFIG, OPTION_VERBOSE, + OPTION_SEEK, }; static constexpr OptionDef option_defs[] = { {"config", 0, true, "Load a MPD configuration file"}, {"verbose", 'v', false, "Verbose logging"}, + {"seek", 0, true, "Seek to this position"}, }; static CommandLine @@ -74,6 +78,10 @@ ParseCommandLine(int argc, char **argv) case OPTION_VERBOSE: c.verbose = true; 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(sample_rate); + } + + void SeekError() noexcept override { + assert(seek_where != SongTime{}); + + seek_error = true; + seek_where = {}; + } +}; + int main(int argc, char **argv) try { const auto c = ParseCommandLine(argc, argv); @@ -115,7 +202,7 @@ try { return EXIT_FAILURE; } - DumpDecoderClient client; + MyDecoderClient client(c.seek_where); if (plugin->file_decode != nullptr) { try { plugin->FileDecode(client, Path::FromFS(c.uri)); @@ -132,10 +219,7 @@ try { return EXIT_FAILURE; } - if (!client.IsInitialized()) { - fprintf(stderr, "Decoding failed\n"); - return EXIT_FAILURE; - } + client.Finish(); return EXIT_SUCCESS; } catch (...) {