input/Stream: remove attribute "cond", replace with handler interface
This adds a bit of overhead, but also adds flexibility to the API, because arbitrary triggers may be invoked from that virtual method implementation, not just Cond::signal(). The motivation for this is to make the handlers more dynamic, for the upcoming buffering class utilizing ProxyInputStream.
This commit is contained in:
parent
01d8eb6290
commit
d0fbf6db59
@ -1382,6 +1382,7 @@ libinput_a_SOURCES = \
|
|||||||
src/input/InputStream.cxx src/input/InputStream.hxx \
|
src/input/InputStream.cxx src/input/InputStream.hxx \
|
||||||
src/input/Ptr.hxx \
|
src/input/Ptr.hxx \
|
||||||
src/input/InputPlugin.hxx \
|
src/input/InputPlugin.hxx \
|
||||||
|
src/input/Handler.hxx \
|
||||||
src/input/RemoteTagScanner.hxx \
|
src/input/RemoteTagScanner.hxx \
|
||||||
src/input/ScanTags.cxx src/input/ScanTags.hxx \
|
src/input/ScanTags.cxx src/input/ScanTags.hxx \
|
||||||
src/input/Reader.cxx src/input/Reader.hxx \
|
src/input/Reader.cxx src/input/Reader.hxx \
|
||||||
|
@ -22,16 +22,14 @@
|
|||||||
#include "TagStream.hxx"
|
#include "TagStream.hxx"
|
||||||
#include "archive/ArchiveFile.hxx"
|
#include "archive/ArchiveFile.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
tag_archive_scan(ArchiveFile &archive, const char *path_utf8,
|
tag_archive_scan(ArchiveFile &archive, const char *path_utf8,
|
||||||
const TagHandler &handler, void *handler_ctx) noexcept
|
const TagHandler &handler, void *handler_ctx) noexcept
|
||||||
try {
|
try {
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto is = archive.OpenStream(path_utf8, mutex, cond);
|
auto is = archive.OpenStream(path_utf8, mutex);
|
||||||
if (!is)
|
if (!is)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -45,9 +43,8 @@ tag_archive_scan(ArchiveFile &archive, const char *path_utf8,
|
|||||||
TagBuilder &builder) noexcept
|
TagBuilder &builder) noexcept
|
||||||
try {
|
try {
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto is = archive.OpenStream(path_utf8, mutex, cond);
|
auto is = archive.OpenStream(path_utf8, mutex);
|
||||||
return is && tag_stream_scan(*is, builder);
|
return is && tag_stream_scan(*is, builder);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#include "decoder/DecoderPlugin.hxx"
|
#include "decoder/DecoderPlugin.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "input/LocalOpen.hxx"
|
#include "input/LocalOpen.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
@ -41,7 +40,6 @@ class TagFileScan {
|
|||||||
void *handler_ctx;
|
void *handler_ctx;
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
InputStreamPtr is;
|
InputStreamPtr is;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -62,8 +60,7 @@ public:
|
|||||||
/* open the InputStream (if not already open) */
|
/* open the InputStream (if not already open) */
|
||||||
if (is == nullptr) {
|
if (is == nullptr) {
|
||||||
try {
|
try {
|
||||||
is = OpenLocalInputStream(path_fs,
|
is = OpenLocalInputStream(path_fs, mutex);
|
||||||
mutex, cond);
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "decoder/DecoderPlugin.hxx"
|
#include "decoder/DecoderPlugin.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
@ -78,9 +77,8 @@ bool
|
|||||||
tag_stream_scan(const char *uri, const TagHandler &handler, void *ctx)
|
tag_stream_scan(const char *uri, const TagHandler &handler, void *ctx)
|
||||||
try {
|
try {
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto is = InputStream::OpenReady(uri, mutex, cond);
|
auto is = InputStream::OpenReady(uri, mutex);
|
||||||
return tag_stream_scan(*is, handler, ctx);
|
return tag_stream_scan(*is, handler, ctx);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
return false;
|
return false;
|
||||||
@ -104,9 +102,8 @@ bool
|
|||||||
tag_stream_scan(const char *uri, TagBuilder &builder)
|
tag_stream_scan(const char *uri, TagBuilder &builder)
|
||||||
try {
|
try {
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto is = InputStream::OpenReady(uri, mutex, cond);
|
auto is = InputStream::OpenReady(uri, mutex);
|
||||||
return tag_stream_scan(*is, builder);
|
return tag_stream_scan(*is, builder);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "input/Ptr.hxx"
|
#include "input/Ptr.hxx"
|
||||||
|
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
class ArchiveVisitor;
|
class ArchiveVisitor;
|
||||||
|
|
||||||
class ArchiveFile {
|
class ArchiveFile {
|
||||||
@ -43,7 +42,7 @@ public:
|
|||||||
* @param path the path within the archive
|
* @param path the path within the archive
|
||||||
*/
|
*/
|
||||||
virtual InputStreamPtr OpenStream(const char *path,
|
virtual InputStreamPtr OpenStream(const char *path,
|
||||||
Mutex &mutex, Cond &cond) = 0;
|
Mutex &mutex) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "../ArchiveVisitor.hxx"
|
#include "../ArchiveVisitor.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "input/LocalOpen.hxx"
|
#include "input/LocalOpen.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
|
|
||||||
#include <bzlib.h>
|
#include <bzlib.h>
|
||||||
@ -54,7 +53,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
InputStreamPtr OpenStream(const char *path,
|
InputStreamPtr OpenStream(const char *path,
|
||||||
Mutex &mutex, Cond &cond) override;
|
Mutex &mutex) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bzip2InputStream final : public InputStream {
|
class Bzip2InputStream final : public InputStream {
|
||||||
@ -69,7 +68,7 @@ class Bzip2InputStream final : public InputStream {
|
|||||||
public:
|
public:
|
||||||
Bzip2InputStream(const std::shared_ptr<InputStream> &_input,
|
Bzip2InputStream(const std::shared_ptr<InputStream> &_input,
|
||||||
const char *uri,
|
const char *uri,
|
||||||
Mutex &mutex, Cond &cond);
|
Mutex &mutex);
|
||||||
~Bzip2InputStream();
|
~Bzip2InputStream();
|
||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
@ -106,8 +105,7 @@ static std::unique_ptr<ArchiveFile>
|
|||||||
bz2_open(Path pathname)
|
bz2_open(Path pathname)
|
||||||
{
|
{
|
||||||
static Mutex mutex;
|
static Mutex mutex;
|
||||||
static Cond cond;
|
auto is = OpenLocalInputStream(pathname, mutex);
|
||||||
auto is = OpenLocalInputStream(pathname, mutex, cond);
|
|
||||||
return std::make_unique<Bzip2ArchiveFile>(pathname, std::move(is));
|
return std::make_unique<Bzip2ArchiveFile>(pathname, std::move(is));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,8 +113,8 @@ bz2_open(Path pathname)
|
|||||||
|
|
||||||
Bzip2InputStream::Bzip2InputStream(const std::shared_ptr<InputStream> &_input,
|
Bzip2InputStream::Bzip2InputStream(const std::shared_ptr<InputStream> &_input,
|
||||||
const char *_uri,
|
const char *_uri,
|
||||||
Mutex &_mutex, Cond &_cond)
|
Mutex &_mutex)
|
||||||
:InputStream(_uri, _mutex, _cond),
|
:InputStream(_uri, _mutex),
|
||||||
input(_input)
|
input(_input)
|
||||||
{
|
{
|
||||||
Open();
|
Open();
|
||||||
@ -129,9 +127,9 @@ Bzip2InputStream::~Bzip2InputStream()
|
|||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
Bzip2ArchiveFile::OpenStream(const char *path,
|
Bzip2ArchiveFile::OpenStream(const char *path,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
return std::make_unique<Bzip2InputStream>(istream, path, mutex, cond);
|
return std::make_unique<Bzip2InputStream>(istream, path, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
@ -75,7 +75,7 @@ public:
|
|||||||
virtual void Visit(ArchiveVisitor &visitor) override;
|
virtual void Visit(ArchiveVisitor &visitor) override;
|
||||||
|
|
||||||
InputStreamPtr OpenStream(const char *path,
|
InputStreamPtr OpenStream(const char *path,
|
||||||
Mutex &mutex, Cond &cond) override;
|
Mutex &mutex) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* archive open && listing routine */
|
/* archive open && listing routine */
|
||||||
@ -144,9 +144,9 @@ class Iso9660InputStream final : public InputStream {
|
|||||||
public:
|
public:
|
||||||
Iso9660InputStream(const std::shared_ptr<Iso9660> &_iso,
|
Iso9660InputStream(const std::shared_ptr<Iso9660> &_iso,
|
||||||
const char *_uri,
|
const char *_uri,
|
||||||
Mutex &_mutex, Cond &_cond,
|
Mutex &_mutex,
|
||||||
iso9660_stat_t *_statbuf)
|
iso9660_stat_t *_statbuf)
|
||||||
:InputStream(_uri, _mutex, _cond),
|
:InputStream(_uri, _mutex),
|
||||||
iso(_iso), statbuf(_statbuf) {
|
iso(_iso), statbuf(_statbuf) {
|
||||||
size = statbuf->size;
|
size = statbuf->size;
|
||||||
SetReady();
|
SetReady();
|
||||||
@ -163,14 +163,14 @@ public:
|
|||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
Iso9660ArchiveFile::OpenStream(const char *pathname,
|
Iso9660ArchiveFile::OpenStream(const char *pathname,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
auto statbuf = iso9660_ifs_stat_translate(iso->iso, pathname);
|
auto statbuf = iso9660_ifs_stat_translate(iso->iso, pathname);
|
||||||
if (statbuf == nullptr)
|
if (statbuf == nullptr)
|
||||||
throw FormatRuntimeError("not found in the ISO file: %s",
|
throw FormatRuntimeError("not found in the ISO file: %s",
|
||||||
pathname);
|
pathname);
|
||||||
|
|
||||||
return std::make_unique<Iso9660InputStream>(iso, pathname, mutex, cond,
|
return std::make_unique<Iso9660InputStream>(iso, pathname, mutex,
|
||||||
statbuf);
|
statbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ public:
|
|||||||
virtual void Visit(ArchiveVisitor &visitor) override;
|
virtual void Visit(ArchiveVisitor &visitor) override;
|
||||||
|
|
||||||
InputStreamPtr OpenStream(const char *path,
|
InputStreamPtr OpenStream(const char *path,
|
||||||
Mutex &mutex, Cond &cond) override;
|
Mutex &mutex) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* archive open && listing routine */
|
/* archive open && listing routine */
|
||||||
@ -92,9 +92,9 @@ class ZzipInputStream final : public InputStream {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ZzipInputStream(const std::shared_ptr<ZzipDir> _dir, const char *_uri,
|
ZzipInputStream(const std::shared_ptr<ZzipDir> _dir, const char *_uri,
|
||||||
Mutex &_mutex, Cond &_cond,
|
Mutex &_mutex,
|
||||||
ZZIP_FILE *_file)
|
ZZIP_FILE *_file)
|
||||||
:InputStream(_uri, _mutex, _cond),
|
:InputStream(_uri, _mutex),
|
||||||
dir(_dir), file(_file) {
|
dir(_dir), file(_file) {
|
||||||
//we are seekable (but its not recommendent to do so)
|
//we are seekable (but its not recommendent to do so)
|
||||||
seekable = true;
|
seekable = true;
|
||||||
@ -118,7 +118,7 @@ public:
|
|||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
ZzipArchiveFile::OpenStream(const char *pathname,
|
ZzipArchiveFile::OpenStream(const char *pathname,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
ZZIP_FILE *_file = zzip_file_open(dir->dir, pathname, 0);
|
ZZIP_FILE *_file = zzip_file_open(dir->dir, pathname, 0);
|
||||||
if (_file == nullptr)
|
if (_file == nullptr)
|
||||||
@ -126,7 +126,7 @@ ZzipArchiveFile::OpenStream(const char *pathname,
|
|||||||
pathname);
|
pathname);
|
||||||
|
|
||||||
return std::make_unique<ZzipInputStream>(dir, pathname,
|
return std::make_unique<ZzipInputStream>(dir, pathname,
|
||||||
mutex, cond,
|
mutex,
|
||||||
_file);
|
_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
#include "LocateUri.hxx"
|
#include "LocateUri.hxx"
|
||||||
#include "TimePrint.hxx"
|
#include "TimePrint.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <inttypes.h> /* for PRIu64 */
|
#include <inttypes.h> /* for PRIu64 */
|
||||||
@ -244,7 +243,7 @@ handle_read_comments(Client &client, Request args, Response &r)
|
|||||||
* opened file or #nullptr on failure.
|
* opened file or #nullptr on failure.
|
||||||
*/
|
*/
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
find_stream_art(const char *directory, Mutex &mutex, Cond &cond)
|
find_stream_art(const char *directory, Mutex &mutex)
|
||||||
{
|
{
|
||||||
static constexpr char const * art_names[] = {
|
static constexpr char const * art_names[] = {
|
||||||
"cover.png",
|
"cover.png",
|
||||||
@ -257,7 +256,7 @@ find_stream_art(const char *directory, Mutex &mutex, Cond &cond)
|
|||||||
std::string art_file = PathTraitsUTF8::Build(directory, name);
|
std::string art_file = PathTraitsUTF8::Build(directory, name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return InputStream::OpenReady(art_file.c_str(), mutex, cond);
|
return InputStream::OpenReady(art_file.c_str(), mutex);
|
||||||
} catch (const std::exception &e) {}
|
} catch (const std::exception &e) {}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -269,9 +268,8 @@ read_stream_art(Response &r, const char *uri, size_t offset)
|
|||||||
std::string art_directory = PathTraitsUTF8::GetParent(uri);
|
std::string art_directory = PathTraitsUTF8::GetParent(uri);
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
InputStreamPtr is = find_stream_art(art_directory.c_str(), mutex, cond);
|
InputStreamPtr is = find_stream_art(art_directory.c_str(), mutex);
|
||||||
|
|
||||||
if (is == nullptr) {
|
if (is == nullptr) {
|
||||||
r.Error(ACK_ERROR_NO_EXIST, "No file exists");
|
r.Error(ACK_ERROR_NO_EXIST, "No file exists");
|
||||||
|
@ -370,7 +370,8 @@ DecoderBridge::OpenUri(const char *uri)
|
|||||||
Mutex &mutex = dc.mutex;
|
Mutex &mutex = dc.mutex;
|
||||||
Cond &cond = dc.cond;
|
Cond &cond = dc.cond;
|
||||||
|
|
||||||
auto is = InputStream::Open(uri, mutex, cond);
|
auto is = InputStream::Open(uri, mutex);
|
||||||
|
is->SetHandler(&dc);
|
||||||
|
|
||||||
const std::lock_guard<Mutex> lock(mutex);
|
const std::lock_guard<Mutex> lock(mutex);
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -404,7 +405,7 @@ try {
|
|||||||
if (is.IsAvailable())
|
if (is.IsAvailable())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
is.cond.wait(is.mutex);
|
dc.cond.wait(is.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nbytes = is.Read(buffer, length);
|
size_t nbytes = is.Read(buffer, length);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "DecoderCommand.hxx"
|
#include "DecoderCommand.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
#include "MixRampInfo.hxx"
|
#include "MixRampInfo.hxx"
|
||||||
|
#include "input/Handler.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "thread/Thread.hxx"
|
#include "thread/Thread.hxx"
|
||||||
@ -60,7 +61,7 @@ enum class DecoderState : uint8_t {
|
|||||||
ERROR,
|
ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DecoderControl {
|
struct DecoderControl final : InputStreamHandler {
|
||||||
/**
|
/**
|
||||||
* The handle of the decoder thread.
|
* The handle of the decoder thread.
|
||||||
*/
|
*/
|
||||||
@ -422,6 +423,15 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void RunThread() noexcept;
|
void RunThread() noexcept;
|
||||||
|
|
||||||
|
/* virtual methods from class InputStreamHandler */
|
||||||
|
void OnInputStreamReady() noexcept override {
|
||||||
|
cond.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnInputStreamAvailable() noexcept override {
|
||||||
|
cond.signal();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -56,7 +56,8 @@ static constexpr Domain decoder_thread_domain("decoder_thread");
|
|||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
decoder_input_stream_open(DecoderControl &dc, const char *uri)
|
decoder_input_stream_open(DecoderControl &dc, const char *uri)
|
||||||
{
|
{
|
||||||
auto is = InputStream::Open(uri, dc.mutex, dc.cond);
|
auto is = InputStream::Open(uri, dc.mutex);
|
||||||
|
is->SetHandler(&dc);
|
||||||
|
|
||||||
/* wait for the input stream to become ready; its metadata
|
/* wait for the input stream to become ready; its metadata
|
||||||
will be available then */
|
will be available then */
|
||||||
@ -81,7 +82,7 @@ decoder_input_stream_open(DecoderControl &dc, const char *uri)
|
|||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
decoder_input_stream_open(DecoderControl &dc, Path path)
|
decoder_input_stream_open(DecoderControl &dc, Path path)
|
||||||
{
|
{
|
||||||
auto is = OpenLocalInputStream(path, dc.mutex, dc.cond);
|
auto is = OpenLocalInputStream(path, dc.mutex);
|
||||||
|
|
||||||
assert(is->IsReady());
|
assert(is->IsReady());
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "AsyncInputStream.hxx"
|
#include "AsyncInputStream.hxx"
|
||||||
|
#include "CondHandler.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "event/Loop.hxx"
|
#include "event/Loop.hxx"
|
||||||
@ -29,10 +30,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
AsyncInputStream::AsyncInputStream(EventLoop &event_loop, const char *_url,
|
AsyncInputStream::AsyncInputStream(EventLoop &event_loop, const char *_url,
|
||||||
Mutex &_mutex, Cond &_cond,
|
Mutex &_mutex,
|
||||||
size_t _buffer_size,
|
size_t _buffer_size,
|
||||||
size_t _resume_at)
|
size_t _resume_at)
|
||||||
:InputStream(_url, _mutex, _cond),
|
:InputStream(_url, _mutex),
|
||||||
deferred_resume(event_loop, BIND_THIS_METHOD(DeferredResume)),
|
deferred_resume(event_loop, BIND_THIS_METHOD(DeferredResume)),
|
||||||
deferred_seek(event_loop, BIND_THIS_METHOD(DeferredSeek)),
|
deferred_seek(event_loop, BIND_THIS_METHOD(DeferredSeek)),
|
||||||
allocation(_buffer_size),
|
allocation(_buffer_size),
|
||||||
@ -133,8 +134,10 @@ AsyncInputStream::Seek(offset_type new_offset)
|
|||||||
|
|
||||||
deferred_seek.Schedule();
|
deferred_seek.Schedule();
|
||||||
|
|
||||||
|
CondInputStreamHandler cond_handler;
|
||||||
|
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
||||||
while (seek_state != SeekState::NONE)
|
while (seek_state != SeekState::NONE)
|
||||||
cond.wait(mutex);
|
cond_handler.cond.wait(mutex);
|
||||||
|
|
||||||
Check();
|
Check();
|
||||||
}
|
}
|
||||||
@ -151,7 +154,7 @@ AsyncInputStream::SeekDone() noexcept
|
|||||||
open = true;
|
open = true;
|
||||||
|
|
||||||
seek_state = SeekState::NONE;
|
seek_state = SeekState::NONE;
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Tag>
|
std::unique_ptr<Tag>
|
||||||
@ -173,6 +176,8 @@ AsyncInputStream::Read(void *ptr, size_t read_size)
|
|||||||
{
|
{
|
||||||
assert(!GetEventLoop().IsInside());
|
assert(!GetEventLoop().IsInside());
|
||||||
|
|
||||||
|
CondInputStreamHandler cond_handler;
|
||||||
|
|
||||||
/* wait for data */
|
/* wait for data */
|
||||||
CircularBuffer<uint8_t>::Range r;
|
CircularBuffer<uint8_t>::Range r;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -182,7 +187,8 @@ AsyncInputStream::Read(void *ptr, size_t read_size)
|
|||||||
if (!r.empty() || IsEOF())
|
if (!r.empty() || IsEOF())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
cond.wait(mutex);
|
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
||||||
|
cond_handler.cond.wait(mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t nbytes = std::min(read_size, r.size);
|
const size_t nbytes = std::min(read_size, r.size);
|
||||||
@ -205,7 +211,7 @@ AsyncInputStream::CommitWriteBuffer(size_t nbytes) noexcept
|
|||||||
if (!IsReady())
|
if (!IsReady())
|
||||||
SetReady();
|
SetReady();
|
||||||
else
|
else
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -231,7 +237,7 @@ AsyncInputStream::AppendToBuffer(const void *data, size_t append_size) noexcept
|
|||||||
if (!IsReady())
|
if (!IsReady())
|
||||||
SetReady();
|
SetReady();
|
||||||
else
|
else
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -243,7 +249,7 @@ AsyncInputStream::DeferredResume() noexcept
|
|||||||
Resume();
|
Resume();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
postponed_exception = std::current_exception();
|
postponed_exception = std::current_exception();
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,6 +271,6 @@ AsyncInputStream::DeferredSeek() noexcept
|
|||||||
} catch (...) {
|
} catch (...) {
|
||||||
seek_state = SeekState::NONE;
|
seek_state = SeekState::NONE;
|
||||||
postponed_exception = std::current_exception();
|
postponed_exception = std::current_exception();
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncInputStream(EventLoop &event_loop, const char *_url,
|
AsyncInputStream(EventLoop &event_loop, const char *_url,
|
||||||
Mutex &_mutex, Cond &_cond,
|
Mutex &_mutex,
|
||||||
size_t _buffer_size,
|
size_t _buffer_size,
|
||||||
size_t _resume_at);
|
size_t _resume_at);
|
||||||
|
|
||||||
|
43
src/input/CondHandler.hxx
Normal file
43
src/input/CondHandler.hxx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2018 The Music Player Daemon Project
|
||||||
|
* http://www.musicpd.org
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPD_COND_INPUT_STREAM_HANDLER_HXX
|
||||||
|
#define MPD_COND_INPUT_STREAM_HANDLER_HXX
|
||||||
|
|
||||||
|
#include "check.h"
|
||||||
|
#include "Handler.hxx"
|
||||||
|
#include "thread/Cond.hxx"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An #InputStreamHandler implementation which signals a #Cond.
|
||||||
|
*/
|
||||||
|
struct CondInputStreamHandler final : InputStreamHandler {
|
||||||
|
Cond cond;
|
||||||
|
|
||||||
|
/* virtual methods from class InputStreamHandler */
|
||||||
|
void OnInputStreamReady() noexcept override {
|
||||||
|
cond.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnInputStreamAvailable() noexcept override {
|
||||||
|
cond.signal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -35,8 +35,8 @@ class FailingInputStream final : public InputStream {
|
|||||||
public:
|
public:
|
||||||
explicit FailingInputStream(const char *_uri,
|
explicit FailingInputStream(const char *_uri,
|
||||||
const std::exception_ptr _error,
|
const std::exception_ptr _error,
|
||||||
Mutex &_mutex, Cond &_cond) noexcept
|
Mutex &_mutex) noexcept
|
||||||
:InputStream(_uri, _mutex, _cond), error(_error) {
|
:InputStream(_uri, _mutex), error(_error) {
|
||||||
SetReady();
|
SetReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
src/input/Handler.hxx
Normal file
53
src/input/Handler.hxx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2018 The Music Player Daemon Project
|
||||||
|
* http://www.musicpd.org
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPD_INPUT_STREAM_HANDLER_HXX
|
||||||
|
#define MPD_INPUT_STREAM_HANDLER_HXX
|
||||||
|
|
||||||
|
#include "check.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface which gets receives events from an #InputStream. Its
|
||||||
|
* methods will be called from within an arbitrary thread and must not
|
||||||
|
* block.
|
||||||
|
*
|
||||||
|
* A reference to an instance is passed to the #InputStream, but it
|
||||||
|
* remains owned by the caller.
|
||||||
|
*/
|
||||||
|
class InputStreamHandler {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Called when InputStream::IsReady() becomes true.
|
||||||
|
*
|
||||||
|
* Before querying metadata from the #InputStream,
|
||||||
|
* InputStream::Update() must be called.
|
||||||
|
*
|
||||||
|
* Caller locks InputStream::mutex.
|
||||||
|
*/
|
||||||
|
virtual void OnInputStreamReady() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when InputStream::IsAvailable() becomes true.
|
||||||
|
*
|
||||||
|
* Caller locks InputStream::mutex.
|
||||||
|
*/
|
||||||
|
virtual void OnInputStreamAvailable() noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
struct ConfigBlock;
|
struct ConfigBlock;
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
class EventLoop;
|
class EventLoop;
|
||||||
class RemoteTagScanner;
|
class RemoteTagScanner;
|
||||||
class RemoteTagHandler;
|
class RemoteTagHandler;
|
||||||
@ -54,8 +53,7 @@ struct InputPlugin {
|
|||||||
*
|
*
|
||||||
* Throws std::runtime_error on error.
|
* Throws std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
InputStreamPtr (*open)(const char *uri,
|
InputStreamPtr (*open)(const char *uri, Mutex &mutex);
|
||||||
Mutex &mutex, Cond &cond);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a #RemoteTagScanner. The operation must be started
|
* Prepare a #RemoteTagScanner. The operation must be started
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
|
#include "Handler.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@ -47,26 +47,8 @@ InputStream::SetReady() noexcept
|
|||||||
assert(!ready);
|
assert(!ready);
|
||||||
|
|
||||||
ready = true;
|
ready = true;
|
||||||
cond.broadcast();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
InvokeOnReady();
|
||||||
InputStream::WaitReady() noexcept
|
|
||||||
{
|
|
||||||
while (true) {
|
|
||||||
Update();
|
|
||||||
if (ready)
|
|
||||||
break;
|
|
||||||
|
|
||||||
cond.wait(mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
InputStream::LockWaitReady() noexcept
|
|
||||||
{
|
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
|
||||||
WaitReady();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,3 +159,17 @@ InputStream::LockIsEOF() noexcept
|
|||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
return IsEOF();
|
return IsEOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputStream::InvokeOnReady() noexcept
|
||||||
|
{
|
||||||
|
if (handler != nullptr)
|
||||||
|
handler->OnInputStreamReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputStream::InvokeOnAvailable() noexcept
|
||||||
|
{
|
||||||
|
if (handler != nullptr)
|
||||||
|
handler->OnInputStreamAvailable();
|
||||||
|
}
|
||||||
|
@ -31,8 +31,8 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
class Cond;
|
|
||||||
struct Tag;
|
struct Tag;
|
||||||
|
class InputStreamHandler;
|
||||||
|
|
||||||
class InputStream {
|
class InputStream {
|
||||||
public:
|
public:
|
||||||
@ -55,6 +55,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
Mutex &mutex;
|
Mutex &mutex;
|
||||||
|
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* A cond that gets signalled when the state of this object
|
* A cond that gets signalled when the state of this object
|
||||||
* changes from the I/O thread. The client of this object may
|
* changes from the I/O thread. The client of this object may
|
||||||
@ -63,7 +64,7 @@ public:
|
|||||||
* This object is allocated by the client, and the client is
|
* This object is allocated by the client, and the client is
|
||||||
* responsible for freeing it.
|
* responsible for freeing it.
|
||||||
*/
|
*/
|
||||||
Cond &cond;
|
InputStreamHandler *handler = nullptr;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -96,9 +97,9 @@ private:
|
|||||||
std::string mime;
|
std::string mime;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InputStream(const char *_uri, Mutex &_mutex, Cond &_cond) noexcept
|
InputStream(const char *_uri, Mutex &_mutex) noexcept
|
||||||
:uri(_uri),
|
:uri(_uri),
|
||||||
mutex(_mutex), cond(_cond) {
|
mutex(_mutex) {
|
||||||
assert(_uri != nullptr);
|
assert(_uri != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,16 +123,33 @@ public:
|
|||||||
* notifications
|
* notifications
|
||||||
* @return an #InputStream object on success
|
* @return an #InputStream object on success
|
||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull(1)
|
||||||
static InputStreamPtr Open(const char *uri, Mutex &mutex, Cond &cond);
|
static InputStreamPtr Open(const char *uri, Mutex &mutex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Just like Open(), but waits for the stream to become ready.
|
* Just like Open(), but waits for the stream to become ready.
|
||||||
* It is a wrapper for Open(), WaitReady() and Check().
|
* It is a wrapper for Open(), WaitReady() and Check().
|
||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull(1)
|
||||||
static InputStreamPtr OpenReady(const char *uri,
|
static InputStreamPtr OpenReady(const char *uri, Mutex &mutex);
|
||||||
Mutex &mutex, Cond &cond);
|
|
||||||
|
/**
|
||||||
|
* Install a new handler.
|
||||||
|
*
|
||||||
|
* The caller must lock the mutex.
|
||||||
|
*/
|
||||||
|
void SetHandler(InputStreamHandler *new_handler) noexcept {
|
||||||
|
handler = new_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a new handler and return the old one.
|
||||||
|
*
|
||||||
|
* The caller must lock the mutex.
|
||||||
|
*/
|
||||||
|
InputStreamHandler *ExchangeHandler(InputStreamHandler *new_handler) noexcept {
|
||||||
|
return std::exchange(handler, new_handler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The absolute URI which was used to open this stream.
|
* The absolute URI which was used to open this stream.
|
||||||
@ -166,14 +184,6 @@ public:
|
|||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitReady() noexcept;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for WaitReady() which locks and unlocks the mutex;
|
|
||||||
* the caller must not be holding it already.
|
|
||||||
*/
|
|
||||||
void LockWaitReady() noexcept;
|
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasMimeType() const noexcept {
|
bool HasMimeType() const noexcept {
|
||||||
assert(ready);
|
assert(ready);
|
||||||
@ -380,6 +390,30 @@ public:
|
|||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
void LockReadFull(void *ptr, size_t size);
|
void LockReadFull(void *ptr, size_t size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InvokeOnReady() noexcept;
|
||||||
|
void InvokeOnAvailable() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install an #InputStreamHandler during the scope in which this
|
||||||
|
* variable lives, and restore the old handler afterwards.
|
||||||
|
*/
|
||||||
|
class ScopeExchangeInputStreamHandler {
|
||||||
|
InputStream &is;
|
||||||
|
InputStreamHandler *const old_handler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScopeExchangeInputStreamHandler(InputStream &_is,
|
||||||
|
InputStreamHandler *new_handler) noexcept
|
||||||
|
:is(_is), old_handler(is.ExchangeHandler(new_handler)) {}
|
||||||
|
|
||||||
|
ScopeExchangeInputStreamHandler(const ScopeExchangeInputStreamHandler &) = delete;
|
||||||
|
|
||||||
|
~ScopeExchangeInputStreamHandler() noexcept {
|
||||||
|
is.SetHandler(old_handler);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,20 +32,20 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond)
|
OpenLocalInputStream(Path path, Mutex &mutex)
|
||||||
{
|
{
|
||||||
InputStreamPtr is;
|
InputStreamPtr is;
|
||||||
|
|
||||||
#ifdef ENABLE_ARCHIVE
|
#ifdef ENABLE_ARCHIVE
|
||||||
try {
|
try {
|
||||||
#endif
|
#endif
|
||||||
is = OpenFileInputStream(path, mutex, cond);
|
is = OpenFileInputStream(path, mutex);
|
||||||
#ifdef ENABLE_ARCHIVE
|
#ifdef ENABLE_ARCHIVE
|
||||||
} catch (const std::system_error &e) {
|
} catch (const std::system_error &e) {
|
||||||
if (IsPathNotFound(e)) {
|
if (IsPathNotFound(e)) {
|
||||||
/* ENOTDIR means this may be a path inside an archive
|
/* ENOTDIR means this may be a path inside an archive
|
||||||
file */
|
file */
|
||||||
is = OpenArchiveInputStream(path, mutex, cond);
|
is = OpenArchiveInputStream(path, mutex);
|
||||||
if (!is)
|
if (!is)
|
||||||
throw;
|
throw;
|
||||||
} else
|
} else
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
class Path;
|
class Path;
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a "local" file. This is a wrapper for the input plugins
|
* Open a "local" file. This is a wrapper for the input plugins
|
||||||
@ -34,6 +33,6 @@ class Cond;
|
|||||||
* Throws std::runtime_error on error.
|
* Throws std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond);
|
OpenLocalInputStream(Path path, Mutex &mutex);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "Registry.hxx"
|
#include "Registry.hxx"
|
||||||
#include "InputPlugin.hxx"
|
#include "InputPlugin.hxx"
|
||||||
#include "LocalOpen.hxx"
|
#include "LocalOpen.hxx"
|
||||||
|
#include "CondHandler.hxx"
|
||||||
#include "RewindInputStream.hxx"
|
#include "RewindInputStream.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
@ -29,16 +30,15 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
InputStream::Open(const char *url,
|
InputStream::Open(const char *url, Mutex &mutex)
|
||||||
Mutex &mutex, Cond &cond)
|
|
||||||
{
|
{
|
||||||
if (PathTraitsUTF8::IsAbsolute(url)) {
|
if (PathTraitsUTF8::IsAbsolute(url)) {
|
||||||
const auto path = AllocatedPath::FromUTF8Throw(url);
|
const auto path = AllocatedPath::FromUTF8Throw(url);
|
||||||
return OpenLocalInputStream(path, mutex, cond);
|
return OpenLocalInputStream(path, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_plugins_for_each_enabled(plugin) {
|
input_plugins_for_each_enabled(plugin) {
|
||||||
auto is = plugin->open(url, mutex, cond);
|
auto is = plugin->open(url, mutex);
|
||||||
if (is != nullptr)
|
if (is != nullptr)
|
||||||
return input_rewind_open(std::move(is));
|
return input_rewind_open(std::move(is));
|
||||||
}
|
}
|
||||||
@ -47,16 +47,27 @@ InputStream::Open(const char *url,
|
|||||||
}
|
}
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
InputStream::OpenReady(const char *uri,
|
InputStream::OpenReady(const char *uri, Mutex &mutex)
|
||||||
Mutex &mutex, Cond &cond)
|
|
||||||
{
|
{
|
||||||
auto is = Open(uri, mutex, cond);
|
CondInputStreamHandler handler;
|
||||||
|
|
||||||
|
auto is = Open(uri, mutex);
|
||||||
|
is->SetHandler(&handler);
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
is->WaitReady();
|
|
||||||
|
while (true) {
|
||||||
|
is->Update();
|
||||||
|
if (is->IsReady())
|
||||||
|
break;
|
||||||
|
|
||||||
|
handler.cond.wait(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
is->Check();
|
is->Check();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is->SetHandler(nullptr);
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
@ -20,15 +20,16 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "ProxyInputStream.hxx"
|
#include "ProxyInputStream.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
ProxyInputStream::ProxyInputStream(InputStreamPtr _input) noexcept
|
ProxyInputStream::ProxyInputStream(InputStreamPtr _input) noexcept
|
||||||
:InputStream(_input->GetURI(), _input->mutex, _input->cond),
|
:InputStream(_input->GetURI(), _input->mutex),
|
||||||
input(std::move(_input))
|
input(std::move(_input))
|
||||||
{
|
{
|
||||||
assert(input);
|
assert(input);
|
||||||
|
|
||||||
|
input->SetHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProxyInputStream::~ProxyInputStream() noexcept = default;
|
ProxyInputStream::~ProxyInputStream() noexcept = default;
|
||||||
@ -40,10 +41,13 @@ ProxyInputStream::SetInput(InputStreamPtr _input) noexcept
|
|||||||
assert(_input);
|
assert(_input);
|
||||||
|
|
||||||
input = std::move(_input);
|
input = std::move(_input);
|
||||||
|
input->SetHandler(this);
|
||||||
|
|
||||||
/* this call wakes up client threads if the new input is
|
/* this call wakes up client threads if the new input is
|
||||||
ready */
|
ready */
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
|
|
||||||
|
set_input_cond.signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -89,7 +93,7 @@ void
|
|||||||
ProxyInputStream::Seek(offset_type new_offset)
|
ProxyInputStream::Seek(offset_type new_offset)
|
||||||
{
|
{
|
||||||
while (!input)
|
while (!input)
|
||||||
cond.wait(mutex);
|
set_input_cond.wait(mutex);
|
||||||
|
|
||||||
input->Seek(new_offset);
|
input->Seek(new_offset);
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
@ -120,7 +124,7 @@ size_t
|
|||||||
ProxyInputStream::Read(void *ptr, size_t read_size)
|
ProxyInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
while (!input)
|
while (!input)
|
||||||
cond.wait(mutex);
|
set_input_cond.wait(mutex);
|
||||||
|
|
||||||
size_t nbytes = input->Read(ptr, read_size);
|
size_t nbytes = input->Read(ptr, read_size);
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
#include "Ptr.hxx"
|
#include "Ptr.hxx"
|
||||||
|
#include "Handler.hxx"
|
||||||
|
#include "thread/Cond.hxx"
|
||||||
|
|
||||||
struct Tag;
|
struct Tag;
|
||||||
|
|
||||||
@ -33,7 +35,9 @@ struct Tag;
|
|||||||
* The inner #InputStream instance may be nullptr initially, to be set
|
* The inner #InputStream instance may be nullptr initially, to be set
|
||||||
* later.
|
* later.
|
||||||
*/
|
*/
|
||||||
class ProxyInputStream : public InputStream {
|
class ProxyInputStream : public InputStream, protected InputStreamHandler {
|
||||||
|
Cond set_input_cond;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InputStreamPtr input;
|
InputStreamPtr input;
|
||||||
|
|
||||||
@ -45,8 +49,8 @@ public:
|
|||||||
* Once that instance becomes available, call SetInput().
|
* Once that instance becomes available, call SetInput().
|
||||||
*/
|
*/
|
||||||
ProxyInputStream(const char *_uri,
|
ProxyInputStream(const char *_uri,
|
||||||
Mutex &_mutex, Cond &_cond) noexcept
|
Mutex &_mutex) noexcept
|
||||||
:InputStream(_uri, _mutex, _cond) {}
|
:InputStream(_uri, _mutex) {}
|
||||||
|
|
||||||
virtual ~ProxyInputStream() noexcept;
|
virtual ~ProxyInputStream() noexcept;
|
||||||
|
|
||||||
@ -78,6 +82,15 @@ protected:
|
|||||||
* attributes.
|
* attributes.
|
||||||
*/
|
*/
|
||||||
void CopyAttributes();
|
void CopyAttributes();
|
||||||
|
|
||||||
|
/* virtual methods from class InputStreamHandler */
|
||||||
|
void OnInputStreamReady() noexcept override {
|
||||||
|
InvokeOnReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnInputStreamAvailable() noexcept override {
|
||||||
|
InvokeOnAvailable();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "ThreadInputStream.hxx"
|
#include "ThreadInputStream.hxx"
|
||||||
|
#include "CondHandler.hxx"
|
||||||
#include "thread/Name.hxx"
|
#include "thread/Name.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -26,9 +27,9 @@
|
|||||||
|
|
||||||
ThreadInputStream::ThreadInputStream(const char *_plugin,
|
ThreadInputStream::ThreadInputStream(const char *_plugin,
|
||||||
const char *_uri,
|
const char *_uri,
|
||||||
Mutex &_mutex, Cond &_cond,
|
Mutex &_mutex,
|
||||||
size_t _buffer_size) noexcept
|
size_t _buffer_size) noexcept
|
||||||
:InputStream(_uri, _mutex, _cond),
|
:InputStream(_uri, _mutex),
|
||||||
plugin(_plugin),
|
plugin(_plugin),
|
||||||
thread(BIND_THIS_METHOD(ThreadFunc)),
|
thread(BIND_THIS_METHOD(ThreadFunc)),
|
||||||
allocation(_buffer_size),
|
allocation(_buffer_size),
|
||||||
@ -94,11 +95,11 @@ ThreadInputStream::ThreadFunc() noexcept
|
|||||||
nbytes = ThreadRead(w.data, w.size);
|
nbytes = ThreadRead(w.data, w.size);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
postponed_exception = std::current_exception();
|
postponed_exception = std::current_exception();
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
|
|
||||||
if (nbytes == 0) {
|
if (nbytes == 0) {
|
||||||
eof = true;
|
eof = true;
|
||||||
@ -134,6 +135,8 @@ ThreadInputStream::Read(void *ptr, size_t read_size)
|
|||||||
{
|
{
|
||||||
assert(!thread.IsInside());
|
assert(!thread.IsInside());
|
||||||
|
|
||||||
|
CondInputStreamHandler cond_handler;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (postponed_exception)
|
if (postponed_exception)
|
||||||
std::rethrow_exception(postponed_exception);
|
std::rethrow_exception(postponed_exception);
|
||||||
@ -151,7 +154,8 @@ ThreadInputStream::Read(void *ptr, size_t read_size)
|
|||||||
if (eof)
|
if (eof)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cond.wait(mutex);
|
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
||||||
|
cond_handler.cond.wait(mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ class ThreadInputStream : public InputStream {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ThreadInputStream(const char *_plugin,
|
ThreadInputStream(const char *_plugin,
|
||||||
const char *_uri, Mutex &_mutex, Cond &_cond,
|
const char *_uri, Mutex &_mutex,
|
||||||
size_t _buffer_size) noexcept;
|
size_t _buffer_size) noexcept;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -75,10 +75,10 @@ class AlsaInputStream final
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AlsaInputStream(EventLoop &_loop,
|
AlsaInputStream(EventLoop &_loop,
|
||||||
const char *_uri, Mutex &_mutex, Cond &_cond,
|
const char *_uri, Mutex &_mutex,
|
||||||
const char *_device,
|
const char *_device,
|
||||||
snd_pcm_t *_handle, int _frame_size)
|
snd_pcm_t *_handle, int _frame_size)
|
||||||
:AsyncInputStream(_loop, _uri, _mutex, _cond,
|
:AsyncInputStream(_loop, _uri, _mutex,
|
||||||
ALSA_MAX_BUFFERED, ALSA_RESUME_AT),
|
ALSA_MAX_BUFFERED, ALSA_RESUME_AT),
|
||||||
MultiSocketMonitor(_loop),
|
MultiSocketMonitor(_loop),
|
||||||
device(_device),
|
device(_device),
|
||||||
@ -111,7 +111,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static InputStreamPtr Create(EventLoop &event_loop, const char *uri,
|
static InputStreamPtr Create(EventLoop &event_loop, const char *uri,
|
||||||
Mutex &mutex, Cond &cond);
|
Mutex &mutex);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* virtual methods from AsyncInputStream */
|
/* virtual methods from AsyncInputStream */
|
||||||
@ -148,7 +148,7 @@ private:
|
|||||||
|
|
||||||
inline InputStreamPtr
|
inline InputStreamPtr
|
||||||
AlsaInputStream::Create(EventLoop &event_loop, const char *uri,
|
AlsaInputStream::Create(EventLoop &event_loop, const char *uri,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
const char *device = StringAfterPrefix(uri, "alsa://");
|
const char *device = StringAfterPrefix(uri, "alsa://");
|
||||||
if (device == nullptr)
|
if (device == nullptr)
|
||||||
@ -168,7 +168,7 @@ AlsaInputStream::Create(EventLoop &event_loop, const char *uri,
|
|||||||
|
|
||||||
int frame_size = snd_pcm_format_width(format) / 8 * channels;
|
int frame_size = snd_pcm_format_width(format) / 8 * channels;
|
||||||
return std::make_unique<AlsaInputStream>(event_loop,
|
return std::make_unique<AlsaInputStream>(event_loop,
|
||||||
uri, mutex, cond,
|
uri, mutex,
|
||||||
device, handle, frame_size);
|
device, handle, frame_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ AlsaInputStream::DispatchSockets() noexcept
|
|||||||
|
|
||||||
if (Recover(n_frames) < 0) {
|
if (Recover(n_frames) < 0) {
|
||||||
postponed_exception = std::make_exception_ptr(std::runtime_error("PCM error - stream aborted"));
|
postponed_exception = std::make_exception_ptr(std::runtime_error("PCM error - stream aborted"));
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -403,10 +403,10 @@ alsa_input_init(EventLoop &event_loop, const ConfigBlock &)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
alsa_input_open(const char *uri, Mutex &mutex, Cond &cond)
|
alsa_input_open(const char *uri, Mutex &mutex)
|
||||||
{
|
{
|
||||||
return AlsaInputStream::Create(*alsa_input_event_loop, uri,
|
return AlsaInputStream::Create(*alsa_input_event_loop, uri,
|
||||||
mutex, cond);
|
mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct InputPlugin input_plugin_alsa = {
|
const struct InputPlugin input_plugin_alsa = {
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond)
|
OpenArchiveInputStream(Path path, Mutex &mutex)
|
||||||
{
|
{
|
||||||
const ArchivePlugin *arplug;
|
const ArchivePlugin *arplug;
|
||||||
|
|
||||||
@ -61,5 +61,5 @@ OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return archive_file_open(arplug, Path::FromFS(archive))
|
return archive_file_open(arplug, Path::FromFS(archive))
|
||||||
->OpenStream(filename, mutex, cond);
|
->OpenStream(filename, mutex);
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,8 @@
|
|||||||
|
|
||||||
class Path;
|
class Path;
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond);
|
OpenArchiveInputStream(Path path, Mutex &mutex);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,11 +61,11 @@ class CdioParanoiaInputStream final : public InputStream {
|
|||||||
int buffer_lsn;
|
int buffer_lsn;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CdioParanoiaInputStream(const char *_uri, Mutex &_mutex, Cond &_cond,
|
CdioParanoiaInputStream(const char *_uri, Mutex &_mutex,
|
||||||
cdrom_drive_t *_drv, CdIo_t *_cdio,
|
cdrom_drive_t *_drv, CdIo_t *_cdio,
|
||||||
bool reverse_endian,
|
bool reverse_endian,
|
||||||
lsn_t _lsn_from, lsn_t _lsn_to)
|
lsn_t _lsn_from, lsn_t _lsn_to)
|
||||||
:InputStream(_uri, _mutex, _cond),
|
:InputStream(_uri, _mutex),
|
||||||
drv(_drv), cdio(_cdio), para(cdio_paranoia_init(drv)),
|
drv(_drv), cdio(_cdio), para(cdio_paranoia_init(drv)),
|
||||||
lsn_from(_lsn_from), lsn_to(_lsn_to),
|
lsn_from(_lsn_from), lsn_to(_lsn_to),
|
||||||
lsn_relofs(0),
|
lsn_relofs(0),
|
||||||
@ -184,7 +184,7 @@ cdio_detect_device(void)
|
|||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
input_cdio_open(const char *uri,
|
input_cdio_open(const char *uri,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
struct cdio_uri parsed_uri;
|
struct cdio_uri parsed_uri;
|
||||||
if (!parse_cdio_uri(&parsed_uri, uri))
|
if (!parse_cdio_uri(&parsed_uri, uri))
|
||||||
@ -250,7 +250,7 @@ input_cdio_open(const char *uri,
|
|||||||
lsn_to = cdio_get_disc_last_lsn(cdio);
|
lsn_to = cdio_get_disc_last_lsn(cdio);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<CdioParanoiaInputStream>(uri, mutex, cond,
|
return std::make_unique<CdioParanoiaInputStream>(uri, mutex,
|
||||||
drv, cdio,
|
drv, cdio,
|
||||||
reverse_endian,
|
reverse_endian,
|
||||||
lsn_from, lsn_to);
|
lsn_from, lsn_to);
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "event/Call.hxx"
|
#include "event/Call.hxx"
|
||||||
#include "event/Loop.hxx"
|
#include "event/Loop.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/StringUtil.hxx"
|
#include "util/StringUtil.hxx"
|
||||||
#include "util/StringFormat.hxx"
|
#include "util/StringFormat.hxx"
|
||||||
@ -83,7 +82,7 @@ public:
|
|||||||
CurlInputStream(EventLoop &event_loop, const char *_url,
|
CurlInputStream(EventLoop &event_loop, const char *_url,
|
||||||
const std::multimap<std::string, std::string> &headers,
|
const std::multimap<std::string, std::string> &headers,
|
||||||
I &&_icy,
|
I &&_icy,
|
||||||
Mutex &_mutex, Cond &_cond);
|
Mutex &_mutex);
|
||||||
|
|
||||||
~CurlInputStream() noexcept;
|
~CurlInputStream() noexcept;
|
||||||
|
|
||||||
@ -92,7 +91,7 @@ public:
|
|||||||
|
|
||||||
static InputStreamPtr Open(const char *url,
|
static InputStreamPtr Open(const char *url,
|
||||||
const std::multimap<std::string, std::string> &headers,
|
const std::multimap<std::string, std::string> &headers,
|
||||||
Mutex &mutex, Cond &cond);
|
Mutex &mutex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -274,7 +273,7 @@ void
|
|||||||
CurlInputStream::OnEnd()
|
CurlInputStream::OnEnd()
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
|
|
||||||
AsyncInputStream::SetClosed();
|
AsyncInputStream::SetClosed();
|
||||||
}
|
}
|
||||||
@ -290,7 +289,7 @@ CurlInputStream::OnError(std::exception_ptr e) noexcept
|
|||||||
else if (!IsReady())
|
else if (!IsReady())
|
||||||
SetReady();
|
SetReady();
|
||||||
else
|
else
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
|
|
||||||
AsyncInputStream::SetClosed();
|
AsyncInputStream::SetClosed();
|
||||||
}
|
}
|
||||||
@ -352,8 +351,8 @@ inline
|
|||||||
CurlInputStream::CurlInputStream(EventLoop &event_loop, const char *_url,
|
CurlInputStream::CurlInputStream(EventLoop &event_loop, const char *_url,
|
||||||
const std::multimap<std::string, std::string> &headers,
|
const std::multimap<std::string, std::string> &headers,
|
||||||
I &&_icy,
|
I &&_icy,
|
||||||
Mutex &_mutex, Cond &_cond)
|
Mutex &_mutex)
|
||||||
:AsyncInputStream(event_loop, _url, _mutex, _cond,
|
:AsyncInputStream(event_loop, _url, _mutex,
|
||||||
CURL_MAX_BUFFERED,
|
CURL_MAX_BUFFERED,
|
||||||
CURL_RESUME_AT),
|
CURL_RESUME_AT),
|
||||||
icy(std::forward<I>(_icy))
|
icy(std::forward<I>(_icy))
|
||||||
@ -445,14 +444,14 @@ CurlInputStream::DoSeek(offset_type new_offset)
|
|||||||
inline InputStreamPtr
|
inline InputStreamPtr
|
||||||
CurlInputStream::Open(const char *url,
|
CurlInputStream::Open(const char *url,
|
||||||
const std::multimap<std::string, std::string> &headers,
|
const std::multimap<std::string, std::string> &headers,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
auto icy = std::make_shared<IcyMetaDataParser>();
|
auto icy = std::make_shared<IcyMetaDataParser>();
|
||||||
|
|
||||||
auto c = std::make_unique<CurlInputStream>((*curl_init)->GetEventLoop(),
|
auto c = std::make_unique<CurlInputStream>((*curl_init)->GetEventLoop(),
|
||||||
url, headers,
|
url, headers,
|
||||||
icy,
|
icy,
|
||||||
mutex, cond);
|
mutex);
|
||||||
|
|
||||||
BlockingCall(c->GetEventLoop(), [&c](){
|
BlockingCall(c->GetEventLoop(), [&c](){
|
||||||
c->InitEasy();
|
c->InitEasy();
|
||||||
@ -465,19 +464,19 @@ CurlInputStream::Open(const char *url,
|
|||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
OpenCurlInputStream(const char *uri,
|
OpenCurlInputStream(const char *uri,
|
||||||
const std::multimap<std::string, std::string> &headers,
|
const std::multimap<std::string, std::string> &headers,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
return CurlInputStream::Open(uri, headers, mutex, cond);
|
return CurlInputStream::Open(uri, headers, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
input_curl_open(const char *url, Mutex &mutex, Cond &cond)
|
input_curl_open(const char *url, Mutex &mutex)
|
||||||
{
|
{
|
||||||
if (strncmp(url, "http://", 7) != 0 &&
|
if (strncmp(url, "http://", 7) != 0 &&
|
||||||
strncmp(url, "https://", 8) != 0)
|
strncmp(url, "https://", 8) != 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return CurlInputStream::Open(url, {}, mutex, cond);
|
return CurlInputStream::Open(url, {}, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct InputPlugin input_plugin_curl = {
|
const struct InputPlugin input_plugin_curl = {
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
|
|
||||||
extern const struct InputPlugin input_plugin_curl;
|
extern const struct InputPlugin input_plugin_curl;
|
||||||
|
|
||||||
@ -40,6 +39,6 @@ extern const struct InputPlugin input_plugin_curl;
|
|||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
OpenCurlInputStream(const char *uri,
|
OpenCurlInputStream(const char *uri,
|
||||||
const std::multimap<std::string, std::string> &headers,
|
const std::multimap<std::string, std::string> &headers,
|
||||||
Mutex &mutex, Cond &cond);
|
Mutex &mutex);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,9 +39,9 @@ struct FfmpegInputStream final : public InputStream {
|
|||||||
|
|
||||||
bool eof;
|
bool eof;
|
||||||
|
|
||||||
FfmpegInputStream(const char *_uri, Mutex &_mutex, Cond &_cond,
|
FfmpegInputStream(const char *_uri, Mutex &_mutex,
|
||||||
AVIOContext *_h)
|
AVIOContext *_h)
|
||||||
:InputStream(_uri, _mutex, _cond),
|
:InputStream(_uri, _mutex),
|
||||||
h(_h), eof(false) {
|
h(_h), eof(false) {
|
||||||
seekable = (h->seekable & AVIO_SEEKABLE_NORMAL) != 0;
|
seekable = (h->seekable & AVIO_SEEKABLE_NORMAL) != 0;
|
||||||
size = avio_size(h);
|
size = avio_size(h);
|
||||||
@ -83,7 +83,7 @@ input_ffmpeg_init(EventLoop &, const ConfigBlock &)
|
|||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
input_ffmpeg_open(const char *uri,
|
input_ffmpeg_open(const char *uri,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
if (!StringStartsWith(uri, "gopher://") &&
|
if (!StringStartsWith(uri, "gopher://") &&
|
||||||
!StringStartsWith(uri, "rtp://") &&
|
!StringStartsWith(uri, "rtp://") &&
|
||||||
@ -98,7 +98,7 @@ input_ffmpeg_open(const char *uri,
|
|||||||
if (result != 0)
|
if (result != 0)
|
||||||
throw MakeFfmpegError(result);
|
throw MakeFfmpegError(result);
|
||||||
|
|
||||||
return std::make_unique<FfmpegInputStream>(uri, mutex, cond, h);
|
return std::make_unique<FfmpegInputStream>(uri, mutex, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
@ -35,8 +35,8 @@ class FileInputStream final : public InputStream {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
FileInputStream(const char *path, FileReader &&_reader, off_t _size,
|
FileInputStream(const char *path, FileReader &&_reader, off_t _size,
|
||||||
Mutex &_mutex, Cond &_cond)
|
Mutex &_mutex)
|
||||||
:InputStream(path, _mutex, _cond),
|
:InputStream(path, _mutex),
|
||||||
reader(std::move(_reader)) {
|
reader(std::move(_reader)) {
|
||||||
size = _size;
|
size = _size;
|
||||||
seekable = true;
|
seekable = true;
|
||||||
@ -54,8 +54,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
OpenFileInputStream(Path path,
|
OpenFileInputStream(Path path, Mutex &mutex)
|
||||||
Mutex &mutex, Cond &cond)
|
|
||||||
{
|
{
|
||||||
FileReader reader(path);
|
FileReader reader(path);
|
||||||
|
|
||||||
@ -75,7 +74,7 @@ OpenFileInputStream(Path path,
|
|||||||
|
|
||||||
return std::make_unique<FileInputStream>(path.ToUTF8().c_str(),
|
return std::make_unique<FileInputStream>(path.ToUTF8().c_str(),
|
||||||
std::move(reader), info.GetSize(),
|
std::move(reader), info.GetSize(),
|
||||||
mutex, cond);
|
mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -24,10 +24,8 @@
|
|||||||
|
|
||||||
class Path;
|
class Path;
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
OpenFileInputStream(Path path,
|
OpenFileInputStream(Path path, Mutex &mutex);
|
||||||
Mutex &mutex, Cond &cond);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,8 +34,8 @@ class MmsInputStream final : public ThreadInputStream {
|
|||||||
mmsx_t *mms;
|
mmsx_t *mms;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MmsInputStream(const char *_uri, Mutex &_mutex, Cond &_cond)
|
MmsInputStream(const char *_uri, Mutex &_mutex)
|
||||||
:ThreadInputStream(input_plugin_mms.name, _uri, _mutex, _cond,
|
:ThreadInputStream(input_plugin_mms.name, _uri, _mutex,
|
||||||
MMS_BUFFER_SIZE) {
|
MMS_BUFFER_SIZE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ MmsInputStream::Open()
|
|||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
input_mms_open(const char *url,
|
input_mms_open(const char *url,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
if (!StringStartsWith(url, "mms://") &&
|
if (!StringStartsWith(url, "mms://") &&
|
||||||
!StringStartsWith(url, "mmsh://") &&
|
!StringStartsWith(url, "mmsh://") &&
|
||||||
@ -78,7 +78,7 @@ input_mms_open(const char *url,
|
|||||||
!StringStartsWith(url, "mmsu://"))
|
!StringStartsWith(url, "mmsu://"))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto m = std::make_unique<MmsInputStream>(url, mutex, cond);
|
auto m = std::make_unique<MmsInputStream>(url, mutex);
|
||||||
m->Start();
|
m->Start();
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "../InputPlugin.hxx"
|
#include "../InputPlugin.hxx"
|
||||||
#include "lib/nfs/Glue.hxx"
|
#include "lib/nfs/Glue.hxx"
|
||||||
#include "lib/nfs/FileReader.hxx"
|
#include "lib/nfs/FileReader.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -46,9 +45,9 @@ class NfsInputStream final : NfsFileReader, public AsyncInputStream {
|
|||||||
bool reconnect_on_resume = false, reconnecting = false;
|
bool reconnect_on_resume = false, reconnecting = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NfsInputStream(const char *_uri, Mutex &_mutex, Cond &_cond)
|
NfsInputStream(const char *_uri, Mutex &_mutex)
|
||||||
:AsyncInputStream(NfsFileReader::GetEventLoop(),
|
:AsyncInputStream(NfsFileReader::GetEventLoop(),
|
||||||
_uri, _mutex, _cond,
|
_uri, _mutex,
|
||||||
NFS_MAX_BUFFERED,
|
NFS_MAX_BUFFERED,
|
||||||
NFS_RESUME_AT) {}
|
NFS_RESUME_AT) {}
|
||||||
|
|
||||||
@ -100,7 +99,7 @@ NfsInputStream::DoRead()
|
|||||||
NfsFileReader::Read(next_offset, nbytes);
|
NfsFileReader::Read(next_offset, nbytes);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
postponed_exception = std::current_exception();
|
postponed_exception = std::current_exception();
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +195,7 @@ NfsInputStream::OnNfsFileError(std::exception_ptr &&e) noexcept
|
|||||||
else if (!IsReady())
|
else if (!IsReady())
|
||||||
SetReady();
|
SetReady();
|
||||||
else
|
else
|
||||||
cond.broadcast();
|
InvokeOnAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -218,12 +217,12 @@ input_nfs_finish() noexcept
|
|||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
input_nfs_open(const char *uri,
|
input_nfs_open(const char *uri,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
if (!StringStartsWith(uri, "nfs://"))
|
if (!StringStartsWith(uri, "nfs://"))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto is = std::make_unique<NfsInputStream>(uri, mutex, cond);
|
auto is = std::make_unique<NfsInputStream>(uri, mutex);
|
||||||
is->Open();
|
is->Open();
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ class QobuzInputStream final
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
QobuzInputStream(const char *_uri, const char *_track_id,
|
QobuzInputStream(const char *_uri, const char *_track_id,
|
||||||
Mutex &_mutex, Cond &_cond) noexcept
|
Mutex &_mutex) noexcept
|
||||||
:ProxyInputStream(_uri, _mutex, _cond),
|
:ProxyInputStream(_uri, _mutex),
|
||||||
track_id(_track_id)
|
track_id(_track_id)
|
||||||
{
|
{
|
||||||
qobuz_client->AddLoginHandler(*this);
|
qobuz_client->AddLoginHandler(*this);
|
||||||
@ -70,7 +70,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void Failed(std::exception_ptr e) {
|
void Failed(std::exception_ptr e) {
|
||||||
SetInput(std::make_unique<FailingInputStream>(GetURI(), e,
|
SetInput(std::make_unique<FailingInputStream>(GetURI(), e,
|
||||||
mutex, cond));
|
mutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from QobuzSessionHandler */
|
/* virtual methods from QobuzSessionHandler */
|
||||||
@ -89,11 +89,11 @@ QobuzInputStream::OnQobuzSession() noexcept
|
|||||||
try {
|
try {
|
||||||
const auto session = qobuz_client->GetSession();
|
const auto session = qobuz_client->GetSession();
|
||||||
|
|
||||||
QobuzTrackHandler &handler = *this;
|
QobuzTrackHandler &h = *this;
|
||||||
track_request = std::make_unique<QobuzTrackRequest>(*qobuz_client,
|
track_request = std::make_unique<QobuzTrackRequest>(*qobuz_client,
|
||||||
session,
|
session,
|
||||||
track_id.c_str(),
|
track_id.c_str(),
|
||||||
handler);
|
h);
|
||||||
track_request->Start();
|
track_request->Start();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
Failed(std::current_exception());
|
Failed(std::current_exception());
|
||||||
@ -108,7 +108,7 @@ QobuzInputStream::OnQobuzTrackSuccess(std::string url) noexcept
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
SetInput(OpenCurlInputStream(url.c_str(), {},
|
SetInput(OpenCurlInputStream(url.c_str(), {},
|
||||||
mutex, cond));
|
mutex));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
Failed(std::current_exception());
|
Failed(std::current_exception());
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ ExtractQobuzTrackId(const char *uri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
OpenQobuzInput(const char *uri, Mutex &mutex, Cond &cond)
|
OpenQobuzInput(const char *uri, Mutex &mutex)
|
||||||
{
|
{
|
||||||
assert(qobuz_client != nullptr);
|
assert(qobuz_client != nullptr);
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ OpenQobuzInput(const char *uri, Mutex &mutex, Cond &cond)
|
|||||||
|
|
||||||
// TODO: validate track_id
|
// TODO: validate track_id
|
||||||
|
|
||||||
return std::make_unique<QobuzInputStream>(uri, track_id, mutex, cond);
|
return std::make_unique<QobuzInputStream>(uri, track_id, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<RemoteTagScanner>
|
static std::unique_ptr<RemoteTagScanner>
|
||||||
|
@ -37,9 +37,9 @@ class SmbclientInputStream final : public InputStream {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SmbclientInputStream(const char *_uri,
|
SmbclientInputStream(const char *_uri,
|
||||||
Mutex &_mutex, Cond &_cond,
|
Mutex &_mutex,
|
||||||
SMBCCTX *_ctx, int _fd, const struct stat &st)
|
SMBCCTX *_ctx, int _fd, const struct stat &st)
|
||||||
:InputStream(_uri, _mutex, _cond),
|
:InputStream(_uri, _mutex),
|
||||||
ctx(_ctx), fd(_fd) {
|
ctx(_ctx), fd(_fd) {
|
||||||
seekable = true;
|
seekable = true;
|
||||||
size = st.st_size;
|
size = st.st_size;
|
||||||
@ -85,7 +85,7 @@ input_smbclient_init(EventLoop &, const ConfigBlock &)
|
|||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
input_smbclient_open(const char *uri,
|
input_smbclient_open(const char *uri,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
if (!StringStartsWith(uri, "smb://"))
|
if (!StringStartsWith(uri, "smb://"))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -119,7 +119,7 @@ input_smbclient_open(const char *uri,
|
|||||||
throw MakeErrno(e, "smbc_fstat() failed");
|
throw MakeErrno(e, "smbc_fstat() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<SmbclientInputStream>(uri, mutex, cond,
|
return std::make_unique<SmbclientInputStream>(uri, mutex,
|
||||||
ctx, fd, st);
|
ctx, fd, st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,8 +60,8 @@ class TidalInputStream final
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
TidalInputStream(const char *_uri, const char *_track_id,
|
TidalInputStream(const char *_uri, const char *_track_id,
|
||||||
Mutex &_mutex, Cond &_cond) noexcept
|
Mutex &_mutex) noexcept
|
||||||
:ProxyInputStream(_uri, _mutex, _cond),
|
:ProxyInputStream(_uri, _mutex),
|
||||||
track_id(_track_id)
|
track_id(_track_id)
|
||||||
{
|
{
|
||||||
tidal_session->AddLoginHandler(*this);
|
tidal_session->AddLoginHandler(*this);
|
||||||
@ -81,7 +81,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void Failed(std::exception_ptr e) {
|
void Failed(std::exception_ptr e) {
|
||||||
SetInput(std::make_unique<FailingInputStream>(GetURI(), e,
|
SetInput(std::make_unique<FailingInputStream>(GetURI(), e,
|
||||||
mutex, cond));
|
mutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from TidalSessionHandler */
|
/* virtual methods from TidalSessionHandler */
|
||||||
@ -98,14 +98,14 @@ TidalInputStream::OnTidalSession() noexcept
|
|||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TidalTrackHandler &handler = *this;
|
TidalTrackHandler &h = *this;
|
||||||
track_request = std::make_unique<TidalTrackRequest>(tidal_session->GetCurl(),
|
track_request = std::make_unique<TidalTrackRequest>(tidal_session->GetCurl(),
|
||||||
tidal_session->GetBaseUrl(),
|
tidal_session->GetBaseUrl(),
|
||||||
tidal_session->GetToken(),
|
tidal_session->GetToken(),
|
||||||
tidal_session->GetSession().c_str(),
|
tidal_session->GetSession().c_str(),
|
||||||
track_id.c_str(),
|
track_id.c_str(),
|
||||||
tidal_audioquality,
|
tidal_audioquality,
|
||||||
handler);
|
h);
|
||||||
track_request->Start();
|
track_request->Start();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
Failed(std::current_exception());
|
Failed(std::current_exception());
|
||||||
@ -124,7 +124,7 @@ TidalInputStream::OnTidalTrackSuccess(std::string url) noexcept
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
SetInput(OpenCurlInputStream(url.c_str(), {},
|
SetInput(OpenCurlInputStream(url.c_str(), {},
|
||||||
mutex, cond));
|
mutex));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
Failed(std::current_exception());
|
Failed(std::current_exception());
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ ExtractTidalTrackId(const char *uri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
OpenTidalInput(const char *uri, Mutex &mutex, Cond &cond)
|
OpenTidalInput(const char *uri, Mutex &mutex)
|
||||||
{
|
{
|
||||||
assert(tidal_session != nullptr);
|
assert(tidal_session != nullptr);
|
||||||
|
|
||||||
@ -221,7 +221,7 @@ OpenTidalInput(const char *uri, Mutex &mutex, Cond &cond)
|
|||||||
|
|
||||||
// TODO: validate track_id
|
// TODO: validate track_id
|
||||||
|
|
||||||
return std::make_unique<TidalInputStream>(uri, track_id, mutex, cond);
|
return std::make_unique<TidalInputStream>(uri, track_id, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<RemoteTagScanner>
|
static std::unique_ptr<RemoteTagScanner>
|
||||||
|
@ -29,13 +29,13 @@ playlist_open_any(const char *uri,
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
const Storage *storage,
|
const Storage *storage,
|
||||||
#endif
|
#endif
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
return uri_has_scheme(uri)
|
return uri_has_scheme(uri)
|
||||||
? playlist_open_remote(uri, mutex, cond)
|
? playlist_open_remote(uri, mutex)
|
||||||
: playlist_mapper_open(uri,
|
: playlist_mapper_open(uri,
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
storage,
|
storage,
|
||||||
#endif
|
#endif
|
||||||
mutex, cond);
|
mutex);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
class SongEnumerator;
|
class SongEnumerator;
|
||||||
class Storage;
|
class Storage;
|
||||||
|
|
||||||
@ -37,6 +36,6 @@ playlist_open_any(const char *uri,
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
const Storage *storage,
|
const Storage *storage,
|
||||||
#endif
|
#endif
|
||||||
Mutex &mutex, Cond &cond);
|
Mutex &mutex);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
* Load a playlist from the configured playlist directory.
|
* Load a playlist from the configured playlist directory.
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<SongEnumerator>
|
static std::unique_ptr<SongEnumerator>
|
||||||
playlist_open_in_playlist_dir(const char *uri, Mutex &mutex, Cond &cond)
|
playlist_open_in_playlist_dir(const char *uri, Mutex &mutex)
|
||||||
{
|
{
|
||||||
assert(spl_valid_name(uri));
|
assert(spl_valid_name(uri));
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ playlist_open_in_playlist_dir(const char *uri, Mutex &mutex, Cond &cond)
|
|||||||
if (path_fs.IsNull())
|
if (path_fs.IsNull())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return playlist_open_path(path_fs, mutex, cond);
|
return playlist_open_path(path_fs, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
@ -50,8 +50,7 @@ playlist_open_in_playlist_dir(const char *uri, Mutex &mutex, Cond &cond)
|
|||||||
* Load a playlist from the configured music directory.
|
* Load a playlist from the configured music directory.
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<SongEnumerator>
|
static std::unique_ptr<SongEnumerator>
|
||||||
playlist_open_in_storage(const char *uri, const Storage *storage,
|
playlist_open_in_storage(const char *uri, const Storage *storage, Mutex &mutex)
|
||||||
Mutex &mutex, Cond &cond)
|
|
||||||
{
|
{
|
||||||
assert(uri_safe_local(uri));
|
assert(uri_safe_local(uri));
|
||||||
|
|
||||||
@ -61,11 +60,11 @@ playlist_open_in_storage(const char *uri, const Storage *storage,
|
|||||||
{
|
{
|
||||||
const auto path = storage->MapFS(uri);
|
const auto path = storage->MapFS(uri);
|
||||||
if (!path.IsNull())
|
if (!path.IsNull())
|
||||||
return playlist_open_path(path, mutex, cond);
|
return playlist_open_path(path, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto uri2 = storage->MapUTF8(uri);
|
const auto uri2 = storage->MapUTF8(uri);
|
||||||
return playlist_open_remote(uri2.c_str(), mutex, cond);
|
return playlist_open_remote(uri2.c_str(), mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -75,19 +74,17 @@ playlist_mapper_open(const char *uri,
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
const Storage *storage,
|
const Storage *storage,
|
||||||
#endif
|
#endif
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
if (spl_valid_name(uri)) {
|
if (spl_valid_name(uri)) {
|
||||||
auto playlist = playlist_open_in_playlist_dir(uri,
|
auto playlist = playlist_open_in_playlist_dir(uri, mutex);
|
||||||
mutex, cond);
|
|
||||||
if (playlist != nullptr)
|
if (playlist != nullptr)
|
||||||
return playlist;
|
return playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
if (uri_safe_local(uri)) {
|
if (uri_safe_local(uri)) {
|
||||||
auto playlist = playlist_open_in_storage(uri, storage,
|
auto playlist = playlist_open_in_storage(uri, storage, mutex);
|
||||||
mutex, cond);
|
|
||||||
if (playlist != nullptr)
|
if (playlist != nullptr)
|
||||||
return playlist;
|
return playlist;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
class SongEnumerator;
|
class SongEnumerator;
|
||||||
class Storage;
|
class Storage;
|
||||||
|
|
||||||
@ -38,6 +37,6 @@ playlist_mapper_open(const char *uri,
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
const Storage *storage,
|
const Storage *storage,
|
||||||
#endif
|
#endif
|
||||||
Mutex &mutex, Cond &cond);
|
Mutex &mutex);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
struct ConfigBlock;
|
struct ConfigBlock;
|
||||||
struct Tag;
|
struct Tag;
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
class SongEnumerator;
|
class SongEnumerator;
|
||||||
|
|
||||||
struct playlist_plugin {
|
struct playlist_plugin {
|
||||||
@ -52,7 +51,7 @@ struct playlist_plugin {
|
|||||||
* either matched one of the schemes or one of the suffixes.
|
* either matched one of the schemes or one of the suffixes.
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<SongEnumerator> (*open_uri)(const char *uri,
|
std::unique_ptr<SongEnumerator> (*open_uri)(const char *uri,
|
||||||
Mutex &mutex, Cond &cond);
|
Mutex &mutex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the playlist in the specified input stream. It has
|
* Opens the playlist in the specified input stream. It has
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "SongEnumerator.hxx"
|
#include "SongEnumerator.hxx"
|
||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
@ -70,13 +69,12 @@ playlist_open_into_queue(const char *uri,
|
|||||||
const SongLoader &loader)
|
const SongLoader &loader)
|
||||||
{
|
{
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto playlist = playlist_open_any(uri,
|
auto playlist = playlist_open_any(uri,
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
loader.GetStorage(),
|
loader.GetStorage(),
|
||||||
#endif
|
#endif
|
||||||
mutex, cond);
|
mutex);
|
||||||
if (playlist == nullptr)
|
if (playlist == nullptr)
|
||||||
throw PlaylistError::NoSuchList();
|
throw PlaylistError::NoSuchList();
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ playlist_list_global_finish() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<SongEnumerator>
|
static std::unique_ptr<SongEnumerator>
|
||||||
playlist_list_open_uri_scheme(const char *uri, Mutex &mutex, Cond &cond,
|
playlist_list_open_uri_scheme(const char *uri, Mutex &mutex,
|
||||||
bool *tried)
|
bool *tried)
|
||||||
{
|
{
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
@ -120,7 +120,7 @@ playlist_list_open_uri_scheme(const char *uri, Mutex &mutex, Cond &cond,
|
|||||||
if (playlist_plugins_enabled[i] && plugin->open_uri != nullptr &&
|
if (playlist_plugins_enabled[i] && plugin->open_uri != nullptr &&
|
||||||
plugin->schemes != nullptr &&
|
plugin->schemes != nullptr &&
|
||||||
StringArrayContainsCase(plugin->schemes, scheme.c_str())) {
|
StringArrayContainsCase(plugin->schemes, scheme.c_str())) {
|
||||||
auto playlist = plugin->open_uri(uri, mutex, cond);
|
auto playlist = plugin->open_uri(uri, mutex);
|
||||||
if (playlist)
|
if (playlist)
|
||||||
return playlist;
|
return playlist;
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ playlist_list_open_uri_scheme(const char *uri, Mutex &mutex, Cond &cond,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<SongEnumerator>
|
static std::unique_ptr<SongEnumerator>
|
||||||
playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
|
playlist_list_open_uri_suffix(const char *uri, Mutex &mutex,
|
||||||
const bool *tried)
|
const bool *tried)
|
||||||
{
|
{
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
@ -148,7 +148,7 @@ playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
|
|||||||
if (playlist_plugins_enabled[i] && !tried[i] &&
|
if (playlist_plugins_enabled[i] && !tried[i] &&
|
||||||
plugin->open_uri != nullptr && plugin->suffixes != nullptr &&
|
plugin->open_uri != nullptr && plugin->suffixes != nullptr &&
|
||||||
StringArrayContainsCase(plugin->suffixes, suffix)) {
|
StringArrayContainsCase(plugin->suffixes, suffix)) {
|
||||||
auto playlist = plugin->open_uri(uri, mutex, cond);
|
auto playlist = plugin->open_uri(uri, mutex);
|
||||||
if (playlist != nullptr)
|
if (playlist != nullptr)
|
||||||
return playlist;
|
return playlist;
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SongEnumerator>
|
std::unique_ptr<SongEnumerator>
|
||||||
playlist_list_open_uri(const char *uri, Mutex &mutex, Cond &cond)
|
playlist_list_open_uri(const char *uri, Mutex &mutex)
|
||||||
{
|
{
|
||||||
/** this array tracks which plugins have already been tried by
|
/** this array tracks which plugins have already been tried by
|
||||||
playlist_list_open_uri_scheme() */
|
playlist_list_open_uri_scheme() */
|
||||||
@ -168,9 +168,9 @@ playlist_list_open_uri(const char *uri, Mutex &mutex, Cond &cond)
|
|||||||
|
|
||||||
memset(tried, false, sizeof(tried));
|
memset(tried, false, sizeof(tried));
|
||||||
|
|
||||||
auto playlist = playlist_list_open_uri_scheme(uri, mutex, cond, tried);
|
auto playlist = playlist_list_open_uri_scheme(uri, mutex, tried);
|
||||||
if (playlist == nullptr)
|
if (playlist == nullptr)
|
||||||
playlist = playlist_list_open_uri_suffix(uri, mutex, cond,
|
playlist = playlist_list_open_uri_suffix(uri, mutex,
|
||||||
tried);
|
tried);
|
||||||
|
|
||||||
return playlist;
|
return playlist;
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
class SongEnumerator;
|
class SongEnumerator;
|
||||||
|
|
||||||
extern const struct playlist_plugin *const playlist_plugins[];
|
extern const struct playlist_plugin *const playlist_plugins[];
|
||||||
@ -51,7 +50,7 @@ playlist_list_global_finish() noexcept;
|
|||||||
* Opens a playlist by its URI.
|
* Opens a playlist by its URI.
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<SongEnumerator>
|
std::unique_ptr<SongEnumerator>
|
||||||
playlist_list_open_uri(const char *uri, Mutex &mutex, Cond &cond);
|
playlist_list_open_uri(const char *uri, Mutex &mutex);
|
||||||
|
|
||||||
std::unique_ptr<SongEnumerator>
|
std::unique_ptr<SongEnumerator>
|
||||||
playlist_list_open_stream_suffix(InputStreamPtr &&is, const char *suffix);
|
playlist_list_open_stream_suffix(InputStreamPtr &&is, const char *suffix);
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
static std::unique_ptr<SongEnumerator>
|
static std::unique_ptr<SongEnumerator>
|
||||||
playlist_open_path_suffix(Path path, Mutex &mutex, Cond &cond)
|
playlist_open_path_suffix(Path path, Mutex &mutex)
|
||||||
try {
|
try {
|
||||||
assert(!path.IsNull());
|
assert(!path.IsNull());
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ try {
|
|||||||
if (!playlist_suffix_supported(suffix_utf8.c_str()))
|
if (!playlist_suffix_supported(suffix_utf8.c_str()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto is = OpenLocalInputStream(path, mutex, cond);
|
auto is = OpenLocalInputStream(path, mutex);
|
||||||
return playlist_list_open_stream_suffix(std::move(is),
|
return playlist_list_open_stream_suffix(std::move(is),
|
||||||
suffix_utf8.c_str());
|
suffix_utf8.c_str());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -53,16 +53,16 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SongEnumerator>
|
std::unique_ptr<SongEnumerator>
|
||||||
playlist_open_path(Path path, Mutex &mutex, Cond &cond)
|
playlist_open_path(Path path, Mutex &mutex)
|
||||||
try {
|
try {
|
||||||
assert(!path.IsNull());
|
assert(!path.IsNull());
|
||||||
|
|
||||||
const std::string uri_utf8 = path.ToUTF8();
|
const std::string uri_utf8 = path.ToUTF8();
|
||||||
auto playlist = !uri_utf8.empty()
|
auto playlist = !uri_utf8.empty()
|
||||||
? playlist_list_open_uri(uri_utf8.c_str(), mutex, cond)
|
? playlist_list_open_uri(uri_utf8.c_str(), mutex)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (playlist == nullptr)
|
if (playlist == nullptr)
|
||||||
playlist = playlist_open_path_suffix(path, mutex, cond);
|
playlist = playlist_open_path_suffix(path, mutex);
|
||||||
|
|
||||||
return playlist;
|
return playlist;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -71,15 +71,15 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SongEnumerator>
|
std::unique_ptr<SongEnumerator>
|
||||||
playlist_open_remote(const char *uri, Mutex &mutex, Cond &cond)
|
playlist_open_remote(const char *uri, Mutex &mutex)
|
||||||
try {
|
try {
|
||||||
assert(uri_has_scheme(uri));
|
assert(uri_has_scheme(uri));
|
||||||
|
|
||||||
auto playlist = playlist_list_open_uri(uri, mutex, cond);
|
auto playlist = playlist_list_open_uri(uri, mutex);
|
||||||
if (playlist != nullptr)
|
if (playlist != nullptr)
|
||||||
return playlist;
|
return playlist;
|
||||||
|
|
||||||
auto is = InputStream::OpenReady(uri, mutex, cond);
|
auto is = InputStream::OpenReady(uri, mutex);
|
||||||
return playlist_list_open_stream(std::move(is), uri);
|
return playlist_list_open_stream(std::move(is), uri);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LogError(std::current_exception());
|
LogError(std::current_exception());
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class Cond;
|
|
||||||
class SongEnumerator;
|
class SongEnumerator;
|
||||||
class Path;
|
class Path;
|
||||||
|
|
||||||
@ -37,10 +36,10 @@ class Path;
|
|||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
std::unique_ptr<SongEnumerator>
|
std::unique_ptr<SongEnumerator>
|
||||||
playlist_open_path(Path path, Mutex &mutex, Cond &cond);
|
playlist_open_path(Path path, Mutex &mutex);
|
||||||
|
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
std::unique_ptr<SongEnumerator>
|
std::unique_ptr<SongEnumerator>
|
||||||
playlist_open_remote(const char *uri, Mutex &mutex, Cond &cond);
|
playlist_open_remote(const char *uri, Mutex &mutex);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "Partition.hxx"
|
#include "Partition.hxx"
|
||||||
#include "Instance.hxx"
|
#include "Instance.hxx"
|
||||||
|
|
||||||
@ -59,7 +58,6 @@ playlist_file_print(Response &r, Partition &partition,
|
|||||||
const char *uri, bool detail)
|
const char *uri, bool detail)
|
||||||
{
|
{
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
#ifndef ENABLE_DATABASE
|
#ifndef ENABLE_DATABASE
|
||||||
(void)partition;
|
(void)partition;
|
||||||
@ -69,7 +67,7 @@ playlist_file_print(Response &r, Partition &partition,
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
partition.instance.storage,
|
partition.instance.storage,
|
||||||
#endif
|
#endif
|
||||||
mutex, cond);
|
mutex);
|
||||||
if (playlist == nullptr)
|
if (playlist == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -89,8 +89,7 @@ static constexpr TagHandler embcue_tag_handler = {
|
|||||||
|
|
||||||
static std::unique_ptr<SongEnumerator>
|
static std::unique_ptr<SongEnumerator>
|
||||||
embcue_playlist_open_uri(const char *uri,
|
embcue_playlist_open_uri(const char *uri,
|
||||||
gcc_unused Mutex &mutex,
|
gcc_unused Mutex &mutex)
|
||||||
gcc_unused Cond &cond)
|
|
||||||
{
|
{
|
||||||
if (!PathTraitsUTF8::IsAbsolute(uri))
|
if (!PathTraitsUTF8::IsAbsolute(uri))
|
||||||
/* only local files supported */
|
/* only local files supported */
|
||||||
|
@ -88,7 +88,7 @@ FlacPlaylist::NextSong()
|
|||||||
|
|
||||||
static std::unique_ptr<SongEnumerator>
|
static std::unique_ptr<SongEnumerator>
|
||||||
flac_playlist_open_uri(const char *uri,
|
flac_playlist_open_uri(const char *uri,
|
||||||
gcc_unused Mutex &mutex, gcc_unused Cond &cond)
|
gcc_unused Mutex &mutex)
|
||||||
{
|
{
|
||||||
if (!PathTraitsUTF8::IsAbsolute(uri))
|
if (!PathTraitsUTF8::IsAbsolute(uri))
|
||||||
/* only local files supported */
|
/* only local files supported */
|
||||||
|
@ -221,9 +221,9 @@ static constexpr yajl_callbacks parse_callbacks = {
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
soundcloud_parse_json(const char *url, Yajl::Handle &handle,
|
soundcloud_parse_json(const char *url, Yajl::Handle &handle,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex)
|
||||||
{
|
{
|
||||||
auto input_stream = InputStream::OpenReady(url, mutex, cond);
|
auto input_stream = InputStream::OpenReady(url, mutex);
|
||||||
Yajl::ParseInputStream(handle, *input_stream);
|
Yajl::ParseInputStream(handle, *input_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +235,7 @@ soundcloud_parse_json(const char *url, Yajl::Handle &handle,
|
|||||||
* soundcloud://url/<url or path of soundcloud page>
|
* soundcloud://url/<url or path of soundcloud page>
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<SongEnumerator>
|
static std::unique_ptr<SongEnumerator>
|
||||||
soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
|
soundcloud_open_uri(const char *uri, Mutex &mutex)
|
||||||
{
|
{
|
||||||
assert(strncmp(uri, "soundcloud://", 13) == 0);
|
assert(strncmp(uri, "soundcloud://", 13) == 0);
|
||||||
uri += 13;
|
uri += 13;
|
||||||
@ -277,7 +277,7 @@ soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
|
|||||||
|
|
||||||
SoundCloudJsonData data;
|
SoundCloudJsonData data;
|
||||||
Yajl::Handle handle(&parse_callbacks, nullptr, &data);
|
Yajl::Handle handle(&parse_callbacks, nullptr, &data);
|
||||||
soundcloud_parse_json(u, handle, mutex, cond);
|
soundcloud_parse_json(u, handle, mutex);
|
||||||
|
|
||||||
data.songs.reverse();
|
data.songs.reverse();
|
||||||
return std::make_unique<MemorySongEnumerator>(std::move(data.songs));
|
return std::make_unique<MemorySongEnumerator>(std::move(data.songs));
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "ApeTag.hxx"
|
#include "ApeTag.hxx"
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "input/LocalOpen.hxx"
|
#include "input/LocalOpen.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
@ -53,9 +52,8 @@ bool
|
|||||||
ScanGenericTags(Path path, const TagHandler &handler, void *ctx)
|
ScanGenericTags(Path path, const TagHandler &handler, void *ctx)
|
||||||
try {
|
try {
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto is = OpenLocalInputStream(path, mutex, cond);
|
auto is = OpenLocalInputStream(path, mutex);
|
||||||
return ScanGenericTags(*is, handler, ctx);
|
return ScanGenericTags(*is, handler, ctx);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LogError(std::current_exception());
|
LogError(std::current_exception());
|
||||||
|
@ -73,7 +73,7 @@ DumpDecoderClient::SeekError()
|
|||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
DumpDecoderClient::OpenUri(const char *uri)
|
DumpDecoderClient::OpenUri(const char *uri)
|
||||||
{
|
{
|
||||||
return InputStream::OpenReady(uri, mutex, cond);
|
return InputStream::OpenReady(uri, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "decoder/Client.hxx"
|
#include "decoder/Client.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A #DecoderClient implementation which dumps metadata to stderr and
|
* A #DecoderClient implementation which dumps metadata to stderr and
|
||||||
@ -36,7 +35,6 @@ class DumpDecoderClient final : public DecoderClient {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
bool IsInitialized() const noexcept {
|
bool IsInitialized() const noexcept {
|
||||||
return initialized;
|
return initialized;
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "tag/ApeLoader.hxx"
|
#include "tag/ApeLoader.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
@ -62,9 +61,8 @@ try {
|
|||||||
const Path path = Path::FromFS(argv[1]);
|
const Path path = Path::FromFS(argv[1]);
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto is = OpenLocalInputStream(path, mutex, cond);
|
auto is = OpenLocalInputStream(path, mutex);
|
||||||
|
|
||||||
if (!tag_ape_scan(*is, MyApeTagCallback)) {
|
if (!tag_ape_scan(*is, MyApeTagCallback)) {
|
||||||
fprintf(stderr, "error\n");
|
fprintf(stderr, "error\n");
|
||||||
|
@ -74,14 +74,13 @@ try {
|
|||||||
/* open the playlist */
|
/* open the playlist */
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
InputStreamPtr is;
|
InputStreamPtr is;
|
||||||
auto playlist = playlist_list_open_uri(uri, mutex, cond);
|
auto playlist = playlist_list_open_uri(uri, mutex);
|
||||||
if (playlist == NULL) {
|
if (playlist == NULL) {
|
||||||
/* open the stream and wait until it becomes ready */
|
/* open the stream and wait until it becomes ready */
|
||||||
|
|
||||||
is = InputStream::OpenReady(uri, mutex, cond);
|
is = InputStream::OpenReady(uri, mutex);
|
||||||
|
|
||||||
/* open the playlist */
|
/* open the playlist */
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "ReplayGainInfo.hxx"
|
#include "ReplayGainInfo.hxx"
|
||||||
#include "config/ConfigGlobal.hxx"
|
#include "config/ConfigGlobal.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "input/LocalOpen.hxx"
|
#include "input/LocalOpen.hxx"
|
||||||
@ -75,9 +74,8 @@ try {
|
|||||||
const Path path = Path::FromFS(argv[1]);
|
const Path path = Path::FromFS(argv[1]);
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto is = OpenLocalInputStream(path, mutex, cond);
|
auto is = OpenLocalInputStream(path, mutex);
|
||||||
|
|
||||||
const auto tag = tag_id3_load(*is);
|
const auto tag = tag_id3_load(*is);
|
||||||
if (tag == NULL) {
|
if (tag == NULL) {
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "input/TextInputStream.hxx"
|
#include "input/TextInputStream.hxx"
|
||||||
#include "config/ConfigGlobal.hxx"
|
#include "config/ConfigGlobal.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
#ifdef ENABLE_ARCHIVE
|
#ifdef ENABLE_ARCHIVE
|
||||||
@ -94,9 +93,8 @@ try {
|
|||||||
/* open the stream and dump it */
|
/* open the stream and dump it */
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
auto is = InputStream::OpenReady(argv[1], mutex, cond);
|
auto is = InputStream::OpenReady(argv[1], mutex);
|
||||||
return dump_input_stream(std::move(is));
|
return dump_input_stream(std::move(is));
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
LogError(e);
|
LogError(e);
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "tag/Handler.hxx"
|
#include "tag/Handler.hxx"
|
||||||
#include "tag/Generic.hxx"
|
#include "tag/Generic.hxx"
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
|
|
||||||
@ -110,11 +109,10 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
InputStreamPtr is;
|
InputStreamPtr is;
|
||||||
|
|
||||||
if (!success && plugin->scan_stream != NULL) {
|
if (!success && plugin->scan_stream != NULL) {
|
||||||
is = InputStream::OpenReady(path.c_str(), mutex, cond);
|
is = InputStream::OpenReady(path.c_str(), mutex);
|
||||||
success = plugin->ScanStream(*is, print_handler, nullptr);
|
success = plugin->ScanStream(*is, print_handler, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +123,7 @@ try {
|
|||||||
if (plugin->file_decode != nullptr) {
|
if (plugin->file_decode != nullptr) {
|
||||||
plugin->FileDecode(client, Path::FromFS(c.uri));
|
plugin->FileDecode(client, Path::FromFS(c.uri));
|
||||||
} else if (plugin->stream_decode != nullptr) {
|
} else if (plugin->stream_decode != nullptr) {
|
||||||
auto is = InputStream::OpenReady(c.uri, client.mutex,
|
auto is = InputStream::OpenReady(c.uri, client.mutex);
|
||||||
client.cond);
|
|
||||||
plugin->StreamDecode(client, *is);
|
plugin->StreamDecode(client, *is);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Decoder plugin is not usable\n");
|
fprintf(stderr, "Decoder plugin is not usable\n");
|
||||||
|
@ -239,8 +239,7 @@ try {
|
|||||||
/* open the stream and dump it */
|
/* open the stream and dump it */
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
auto is = InputStream::OpenReady(c.uri, mutex);
|
||||||
auto is = InputStream::OpenReady(c.uri, mutex, cond);
|
|
||||||
return dump_input_stream(is.get());
|
return dump_input_stream(is.get());
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
LogError(e);
|
LogError(e);
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "input/RewindInputStream.hxx"
|
#include "input/RewindInputStream.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
|
||||||
|
|
||||||
#include <cppunit/TestFixture.h>
|
#include <cppunit/TestFixture.h>
|
||||||
#include <cppunit/extensions/TestFactoryRegistry.h>
|
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||||
@ -24,9 +23,9 @@ class StringInputStream final : public InputStream {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
StringInputStream(const char *_uri,
|
StringInputStream(const char *_uri,
|
||||||
Mutex &_mutex, Cond &_cond,
|
Mutex &_mutex,
|
||||||
const char *_data)
|
const char *_data)
|
||||||
:InputStream(_uri, _mutex, _cond),
|
:InputStream(_uri, _mutex),
|
||||||
data(_data), remaining(strlen(data)) {
|
data(_data), remaining(strlen(data)) {
|
||||||
SetReady();
|
SetReady();
|
||||||
}
|
}
|
||||||
@ -54,10 +53,9 @@ class RewindTest : public CppUnit::TestFixture {
|
|||||||
public:
|
public:
|
||||||
void TestRewind() {
|
void TestRewind() {
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
|
||||||
|
|
||||||
StringInputStream *sis =
|
StringInputStream *sis =
|
||||||
new StringInputStream("foo://", mutex, cond,
|
new StringInputStream("foo://", mutex,
|
||||||
"foo bar");
|
"foo bar");
|
||||||
CPPUNIT_ASSERT(sis->IsReady());
|
CPPUNIT_ASSERT(sis->IsReady());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user