input/thread: use C++ exceptions instead of class Error
This commit is contained in:
parent
3cd07d0b54
commit
597e59f10d
@ -64,7 +64,10 @@ ThreadInputStream::ThreadFunc()
|
|||||||
|
|
||||||
const ScopeLock lock(mutex);
|
const ScopeLock lock(mutex);
|
||||||
|
|
||||||
if (!Open(postponed_error)) {
|
try {
|
||||||
|
Open();
|
||||||
|
} catch (...) {
|
||||||
|
postponed_exception = std::current_exception();
|
||||||
cond.broadcast();
|
cond.broadcast();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -73,25 +76,27 @@ ThreadInputStream::ThreadFunc()
|
|||||||
SetReady();
|
SetReady();
|
||||||
|
|
||||||
while (!close) {
|
while (!close) {
|
||||||
assert(!postponed_error.IsDefined());
|
assert(!postponed_exception);
|
||||||
|
|
||||||
auto w = buffer->Write();
|
auto w = buffer->Write();
|
||||||
if (w.IsEmpty()) {
|
if (w.IsEmpty()) {
|
||||||
wake_cond.wait(mutex);
|
wake_cond.wait(mutex);
|
||||||
} else {
|
} else {
|
||||||
Error error;
|
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
|
||||||
{
|
try {
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
nbytes = ThreadRead(w.data, w.size, error);
|
nbytes = ThreadRead(w.data, w.size);
|
||||||
|
} catch (...) {
|
||||||
|
postponed_exception = std::current_exception();
|
||||||
|
cond.broadcast();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cond.broadcast();
|
cond.broadcast();
|
||||||
|
|
||||||
if (nbytes == 0) {
|
if (nbytes == 0) {
|
||||||
eof = true;
|
eof = true;
|
||||||
postponed_error = std::move(error);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,14 +115,12 @@ ThreadInputStream::ThreadFunc(void *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ThreadInputStream::Check(Error &error)
|
ThreadInputStream::Check(Error &)
|
||||||
{
|
{
|
||||||
assert(!thread.IsInside());
|
assert(!thread.IsInside());
|
||||||
|
|
||||||
if (postponed_error.IsDefined()) {
|
if (postponed_exception)
|
||||||
error = std::move(postponed_error);
|
std::rethrow_exception(postponed_exception);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -127,19 +130,17 @@ ThreadInputStream::IsAvailable()
|
|||||||
{
|
{
|
||||||
assert(!thread.IsInside());
|
assert(!thread.IsInside());
|
||||||
|
|
||||||
return !buffer->IsEmpty() || eof || postponed_error.IsDefined();
|
return !buffer->IsEmpty() || eof || postponed_exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
ThreadInputStream::Read(void *ptr, size_t read_size, Error &error)
|
ThreadInputStream::Read(void *ptr, size_t read_size, Error &)
|
||||||
{
|
{
|
||||||
assert(!thread.IsInside());
|
assert(!thread.IsInside());
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (postponed_error.IsDefined()) {
|
if (postponed_exception)
|
||||||
error = std::move(postponed_error);
|
std::rethrow_exception(postponed_exception);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto r = buffer->Read();
|
auto r = buffer->Read();
|
||||||
if (!r.IsEmpty()) {
|
if (!r.IsEmpty()) {
|
||||||
|
@ -24,7 +24,8 @@
|
|||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
#include "thread/Thread.hxx"
|
#include "thread/Thread.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ class ThreadInputStream : public InputStream {
|
|||||||
*/
|
*/
|
||||||
Cond wake_cond;
|
Cond wake_cond;
|
||||||
|
|
||||||
Error postponed_error;
|
std::exception_ptr postponed_exception;
|
||||||
|
|
||||||
const size_t buffer_size;
|
const size_t buffer_size;
|
||||||
CircularBuffer<uint8_t> *buffer = nullptr;
|
CircularBuffer<uint8_t> *buffer = nullptr;
|
||||||
@ -103,9 +104,10 @@ protected:
|
|||||||
*
|
*
|
||||||
* The #InputStream is locked. Unlock/relock it if you do a
|
* The #InputStream is locked. Unlock/relock it if you do a
|
||||||
* blocking operation.
|
* blocking operation.
|
||||||
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
virtual bool Open(gcc_unused Error &error) {
|
virtual void Open() {
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,9 +115,11 @@ protected:
|
|||||||
*
|
*
|
||||||
* The #InputStream is not locked.
|
* The #InputStream is not locked.
|
||||||
*
|
*
|
||||||
* @return 0 on end-of-file or on error
|
* Throws std::runtime_error on error.
|
||||||
|
*
|
||||||
|
* @return 0 on end-of-file
|
||||||
*/
|
*/
|
||||||
virtual size_t ThreadRead(void *ptr, size_t size, Error &error) = 0;
|
virtual size_t ThreadRead(void *ptr, size_t size) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional deinitialization before leaving the thread.
|
* Optional deinitialization before leaving the thread.
|
||||||
|
@ -21,12 +21,13 @@
|
|||||||
#include "MmsInputPlugin.hxx"
|
#include "MmsInputPlugin.hxx"
|
||||||
#include "input/ThreadInputStream.hxx"
|
#include "input/ThreadInputStream.hxx"
|
||||||
#include "input/InputPlugin.hxx"
|
#include "input/InputPlugin.hxx"
|
||||||
|
#include "system/Error.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/Domain.hxx"
|
|
||||||
|
|
||||||
#include <libmms/mmsx.h>
|
#include <libmms/mmsx.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
static constexpr size_t MMS_BUFFER_SIZE = 256 * 1024;
|
static constexpr size_t MMS_BUFFER_SIZE = 256 * 1024;
|
||||||
|
|
||||||
class MmsInputStream final : public ThreadInputStream {
|
class MmsInputStream final : public ThreadInputStream {
|
||||||
@ -39,27 +40,23 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool Open(gcc_unused Error &error) override;
|
virtual void Open() override;
|
||||||
virtual size_t ThreadRead(void *ptr, size_t size,
|
virtual size_t ThreadRead(void *ptr, size_t size) override;
|
||||||
Error &error) override;
|
|
||||||
|
|
||||||
void Close() override {
|
void Close() override {
|
||||||
mmsx_close(mms);
|
mmsx_close(mms);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Domain mms_domain("mms");
|
void
|
||||||
|
MmsInputStream::Open()
|
||||||
bool
|
|
||||||
MmsInputStream::Open(Error &error)
|
|
||||||
{
|
{
|
||||||
Unlock();
|
Unlock();
|
||||||
|
|
||||||
mms = mmsx_connect(nullptr, nullptr, GetURI(), 128 * 1024);
|
mms = mmsx_connect(nullptr, nullptr, GetURI(), 128 * 1024);
|
||||||
if (mms == nullptr) {
|
if (mms == nullptr) {
|
||||||
Lock();
|
Lock();
|
||||||
error.Set(mms_domain, "mmsx_connect() failed");
|
throw std::runtime_error("mmsx_connect() failed");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Lock();
|
Lock();
|
||||||
@ -67,7 +64,6 @@ MmsInputStream::Open(Error &error)
|
|||||||
/* TODO: is this correct? at least this selects the ffmpeg
|
/* TODO: is this correct? at least this selects the ffmpeg
|
||||||
decoder, which seems to work fine */
|
decoder, which seems to work fine */
|
||||||
SetMimeType("audio/x-ms-wma");
|
SetMimeType("audio/x-ms-wma");
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static InputStream *
|
static InputStream *
|
||||||
@ -86,7 +82,7 @@ input_mms_open(const char *url,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
MmsInputStream::ThreadRead(void *ptr, size_t read_size, Error &error)
|
MmsInputStream::ThreadRead(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
/* unfortunately, mmsx_read() blocks until the whole buffer
|
/* unfortunately, mmsx_read() blocks until the whole buffer
|
||||||
has been filled; to avoid big latencies, limit the size of
|
has been filled; to avoid big latencies, limit the size of
|
||||||
@ -98,7 +94,7 @@ MmsInputStream::ThreadRead(void *ptr, size_t read_size, Error &error)
|
|||||||
int nbytes = mmsx_read(nullptr, mms, (char *)ptr, read_size);
|
int nbytes = mmsx_read(nullptr, mms, (char *)ptr, read_size);
|
||||||
if (nbytes <= 0) {
|
if (nbytes <= 0) {
|
||||||
if (nbytes < 0)
|
if (nbytes < 0)
|
||||||
error.SetErrno("mmsx_read() failed");
|
throw MakeErrno("mmsx_read() failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user