Skip to content

Commit 58d386a

Browse files
committed
decoder/Client: pass std::exception_ptr to method SeekError()
This allows decoder plugins to show detailed seek errors that will be included in the seek error message in the MPD protocol. Currently, this new parameter is optional, and some decoders may never pass details because they don't have any.
1 parent e4367a0 commit 58d386a

20 files changed

Lines changed: 91 additions & 69 deletions

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ ver 0.25 (not yet released)
22
* protocol
33
- implement "window" parameter for command "list"
44
- new command "stringnormalization"
5+
- show detailed seek errors
56
* decoder
67
- vgmstream: new plugin
78
* output

src/decoder/Bridge.cxx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,24 +348,27 @@ DecoderBridge::GetSeekFrame() noexcept
348348
}
349349

350350
void
351-
DecoderBridge::SeekError() noexcept
351+
DecoderBridge::SeekError(std::exception_ptr &&_error) noexcept
352352
{
353353
assert(dc.pipe != nullptr);
354354

355+
if (!_error)
356+
_error = std::make_exception_ptr(std::runtime_error{"Decoder failed to seek"});
357+
355358
if (initial_seek_running) {
356359
/* d'oh, we can't seek to the sub-song start position,
357360
what now? - no idea, ignoring the problem for now. */
358361
initial_seek_running = false;
359362

360363
if (initial_seek_essential)
361-
error = std::make_exception_ptr(std::runtime_error("Decoder failed to seek"));
364+
error = std::move(_error);
362365

363366
return;
364367
}
365368

366369
assert(dc.command == DecoderCommand::SEEK);
367370

368-
dc.seek_error = true;
371+
dc.seek_error = std::move(_error);
369372
seeking = false;
370373

371374
CommandFinished();

src/decoder/Bridge.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public:
157157
void CommandFinished() noexcept override;
158158
SongTime GetSeekTime() noexcept override;
159159
uint64_t GetSeekFrame() noexcept override;
160-
void SeekError() noexcept override;
160+
void SeekError(std::exception_ptr &&_error) noexcept override;
161161
InputStreamPtr OpenUri(std::string_view uri) override;
162162
size_t Read(InputStream &is,
163163
std::span<std::byte> dest) noexcept override;

src/decoder/Client.hxx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <cstddef>
1111
#include <cstdint>
12+
#include <exception>
1213
#include <span>
1314
#include <string_view>
1415

@@ -71,8 +72,10 @@ public:
7172
/**
7273
* Call this instead of CommandFinished() when seeking has
7374
* failed.
75+
*
76+
* @param error details about the seek error (optional)
7477
*/
75-
virtual void SeekError() noexcept = 0;
78+
virtual void SeekError(std::exception_ptr &&error={}) noexcept = 0;
7679

7780
/**
7881
* Open a new #InputStream and wait until it's ready.

src/decoder/Control.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ DecoderControl::Seek(std::unique_lock<Mutex> &lock, SongTime t)
119119
throw std::runtime_error("Not seekable");
120120

121121
seek_time = t;
122-
seek_error = false;
122+
seek_error = {};
123123
SynchronousCommandLocked(lock, DecoderCommand::SEEK);
124124

125125
while (state == DecoderState::START)
@@ -135,7 +135,7 @@ DecoderControl::Seek(std::unique_lock<Mutex> &lock, SongTime t)
135135
WaitForDecoder(lock);
136136

137137
if (seek_error)
138-
throw std::runtime_error("Decoder failed to seek");
138+
std::rethrow_exception(seek_error);
139139
}
140140

141141
void

src/decoder/Control.hxx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,15 @@ public:
9090
*/
9191
std::exception_ptr error;
9292

93+
/**
94+
* The most recent seek error.
95+
*/
96+
std::exception_ptr seek_error;
97+
9398
private:
9499
bool quit;
95100

96101
public:
97-
bool seek_error;
98102
bool seekable;
99103

100104
/**

src/decoder/plugins/DsdiffDecoderPlugin.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ dsdiff_decode_chunk(DecoderClient &client, InputStream &is,
385385
} else
386386
client.SeekError();
387387
} catch (...) {
388-
client.SeekError();
388+
client.SeekError(std::current_exception());
389389
}
390390
}
391391

src/decoder/plugins/DsfDecoderPlugin.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ dsf_decode_chunk(DecoderClient &client, InputStream &is,
265265
} else
266266
client.SeekError();
267267
} catch (...) {
268-
client.SeekError();
268+
client.SeekError(std::current_exception());
269269
}
270270
}
271271

src/decoder/plugins/FfmpegDecoderPlugin.cxx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -543,9 +543,10 @@ FfmpegDecode(DecoderClient &client, InputStream *input,
543543
/* AVSEEK_FLAG_BACKWARD asks FFmpeg to seek to
544544
the packet boundary before the seek time
545545
stamp, not after */
546-
if (av_seek_frame(&format_context, audio_stream, where,
547-
AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0)
548-
client.SeekError();
546+
if (int error = av_seek_frame(&format_context, audio_stream, where,
547+
AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD);
548+
error < 0)
549+
client.SeekError(std::make_exception_ptr(MakeFfmpegError(error, "av_seek_frame() failed")));
549550
else {
550551
codec_context.FlushBuffers();
551552
min_frame = client.GetSeekFrame();

src/decoder/plugins/GmeDecoderPlugin.cxx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "fs/FileSystem.hxx"
1414
#include "fs/NarrowPath.hxx"
1515
#include "lib/fmt/PathFormatter.hxx"
16+
#include "lib/fmt/RuntimeError.hxx"
1617
#include "util/ScopeExit.hxx"
1718
#include "util/StringCompare.hxx"
1819
#include "util/Domain.hxx"
@@ -28,6 +29,8 @@
2829

2930
#define SUBTUNE_PREFIX "tune_"
3031

32+
using std::string_view_literals::operator""sv;
33+
3134
static constexpr Domain gme_domain("gme");
3235

3336
static constexpr unsigned GME_SAMPLE_RATE = 44100;
@@ -202,8 +205,7 @@ gme_file_decode(DecoderClient &client, Path path_fs)
202205
unsigned where = client.GetSeekTime().ToMS();
203206
gme_err = gme_seek(emu, where);
204207
if (gme_err != nullptr) {
205-
LogWarning(gme_domain, gme_err);
206-
client.SeekError();
208+
client.SeekError(std::make_exception_ptr(FmtRuntimeError("gme_see() failed: {}"sv, gme_err)));
207209
} else
208210
client.CommandFinished();
209211
}

0 commit comments

Comments
 (0)