input/plugins: make InputStream the base class
Prepare for adding virtual methods.
This commit is contained in:
parent
e1383a2d8e
commit
f1d0700252
@ -88,9 +88,7 @@ public:
|
|||||||
Error &error) override;
|
Error &error) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bzip2InputStream {
|
struct Bzip2InputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
Bzip2ArchiveFile *archive;
|
Bzip2ArchiveFile *archive;
|
||||||
|
|
||||||
bool eof;
|
bool eof;
|
||||||
@ -130,7 +128,7 @@ Bzip2InputStream::Open(Error &error)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.ready = true;
|
SetReady();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,9 +155,10 @@ bz2_open(Path pathname, Error &error)
|
|||||||
|
|
||||||
/* single archive handling */
|
/* single archive handling */
|
||||||
|
|
||||||
Bzip2InputStream::Bzip2InputStream(Bzip2ArchiveFile &_context, const char *uri,
|
Bzip2InputStream::Bzip2InputStream(Bzip2ArchiveFile &_context,
|
||||||
Mutex &mutex, Cond &cond)
|
const char *_uri,
|
||||||
:base(bz2_inputplugin, uri, mutex, cond),
|
Mutex &_mutex, Cond &_cond)
|
||||||
|
:InputStream(bz2_inputplugin, _uri, _mutex, _cond),
|
||||||
archive(&_context), eof(false)
|
archive(&_context), eof(false)
|
||||||
{
|
{
|
||||||
archive->Ref();
|
archive->Ref();
|
||||||
@ -181,7 +180,7 @@ Bzip2ArchiveFile::OpenStream(const char *path,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return &bis->base;
|
return bis;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -140,21 +140,19 @@ Iso9660ArchiveFile::Visit(ArchiveVisitor &visitor)
|
|||||||
|
|
||||||
/* single archive handling */
|
/* single archive handling */
|
||||||
|
|
||||||
class Iso9660InputStream {
|
class Iso9660InputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
Iso9660ArchiveFile &archive;
|
Iso9660ArchiveFile &archive;
|
||||||
|
|
||||||
iso9660_stat_t *statbuf;
|
iso9660_stat_t *statbuf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Iso9660InputStream(Iso9660ArchiveFile &_archive, const char *uri,
|
Iso9660InputStream(Iso9660ArchiveFile &_archive, const char *_uri,
|
||||||
Mutex &mutex, Cond &cond,
|
Mutex &_mutex, Cond &_cond,
|
||||||
iso9660_stat_t *_statbuf)
|
iso9660_stat_t *_statbuf)
|
||||||
:base(iso9660_input_plugin, uri, mutex, cond),
|
:InputStream(iso9660_input_plugin, _uri, _mutex, _cond),
|
||||||
archive(_archive), statbuf(_statbuf) {
|
archive(_archive), statbuf(_statbuf) {
|
||||||
base.ready = true;
|
size = statbuf->size;
|
||||||
base.size = statbuf->size;
|
SetReady();
|
||||||
|
|
||||||
archive.Ref();
|
archive.Ref();
|
||||||
}
|
}
|
||||||
@ -164,10 +162,6 @@ public:
|
|||||||
archive.Unref();
|
archive.Unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream *Get() {
|
|
||||||
return &base;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size, Error &error);
|
size_t Read(void *ptr, size_t size, Error &error);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,10 +177,8 @@ Iso9660ArchiveFile::OpenStream(const char *pathname,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso9660InputStream *iis =
|
return new Iso9660InputStream(*this, pathname, mutex, cond,
|
||||||
new Iso9660InputStream(*this, pathname, mutex, cond,
|
statbuf);
|
||||||
statbuf);
|
|
||||||
return iis->Get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -198,22 +190,22 @@ iso9660_input_close(InputStream *is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
Iso9660InputStream::Read(void *ptr, size_t size, Error &error)
|
Iso9660InputStream::Read(void *ptr, size_t read_size, Error &error)
|
||||||
{
|
{
|
||||||
int readed = 0;
|
int readed = 0;
|
||||||
int no_blocks, cur_block;
|
int no_blocks, cur_block;
|
||||||
size_t left_bytes = statbuf->size - base.offset;
|
size_t left_bytes = statbuf->size - offset;
|
||||||
|
|
||||||
if (left_bytes < size) {
|
if (left_bytes < read_size) {
|
||||||
no_blocks = CEILING(left_bytes,ISO_BLOCKSIZE);
|
no_blocks = CEILING(left_bytes, ISO_BLOCKSIZE);
|
||||||
} else {
|
} else {
|
||||||
no_blocks = size / ISO_BLOCKSIZE;
|
no_blocks = read_size / ISO_BLOCKSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (no_blocks == 0)
|
if (no_blocks == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cur_block = base.offset / ISO_BLOCKSIZE;
|
cur_block = offset / ISO_BLOCKSIZE;
|
||||||
|
|
||||||
readed = archive.SeekRead(ptr, statbuf->lsn + cur_block,
|
readed = archive.SeekRead(ptr, statbuf->lsn + cur_block,
|
||||||
no_blocks);
|
no_blocks);
|
||||||
@ -224,11 +216,11 @@ Iso9660InputStream::Read(void *ptr, size_t size, Error &error)
|
|||||||
(unsigned long)cur_block);
|
(unsigned long)cur_block);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (left_bytes < size) {
|
if (left_bytes < read_size) {
|
||||||
readed = left_bytes;
|
readed = left_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.offset += readed;
|
offset += readed;
|
||||||
return readed;
|
return readed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,25 +97,24 @@ ZzipArchiveFile::Visit(ArchiveVisitor &visitor)
|
|||||||
|
|
||||||
/* single archive handling */
|
/* single archive handling */
|
||||||
|
|
||||||
struct ZzipInputStream {
|
struct ZzipInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
ZzipArchiveFile *archive;
|
ZzipArchiveFile *archive;
|
||||||
|
|
||||||
ZZIP_FILE *file;
|
ZZIP_FILE *file;
|
||||||
|
|
||||||
ZzipInputStream(ZzipArchiveFile &_archive, const char *uri,
|
ZzipInputStream(ZzipArchiveFile &_archive, const char *_uri,
|
||||||
Mutex &mutex, Cond &cond,
|
Mutex &_mutex, Cond &_cond,
|
||||||
ZZIP_FILE *_file)
|
ZZIP_FILE *_file)
|
||||||
:base(zzip_input_plugin, uri, mutex, cond),
|
:InputStream(zzip_input_plugin, _uri, _mutex, _cond),
|
||||||
archive(&_archive), file(_file) {
|
archive(&_archive), file(_file) {
|
||||||
base.ready = true;
|
|
||||||
//we are seekable (but its not recommendent to do so)
|
//we are seekable (but its not recommendent to do so)
|
||||||
base.seekable = true;
|
seekable = true;
|
||||||
|
|
||||||
ZZIP_STAT z_stat;
|
ZZIP_STAT z_stat;
|
||||||
zzip_file_stat(file, &z_stat);
|
zzip_file_stat(file, &z_stat);
|
||||||
base.size = z_stat.st_size;
|
size = z_stat.st_size;
|
||||||
|
|
||||||
|
SetReady();
|
||||||
|
|
||||||
archive->ref.Increment();
|
archive->ref.Increment();
|
||||||
}
|
}
|
||||||
@ -138,11 +137,9 @@ ZzipArchiveFile::OpenStream(const char *pathname,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZzipInputStream *zis =
|
return new ZzipInputStream(*this, pathname,
|
||||||
new ZzipInputStream(*this, pathname,
|
mutex, cond,
|
||||||
mutex, cond,
|
_file);
|
||||||
_file);
|
|
||||||
return &zis->base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -52,30 +52,30 @@ ThreadInputStream::Start(Error &error)
|
|||||||
if (!thread.Start(ThreadFunc, this, error))
|
if (!thread.Start(ThreadFunc, this, error))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return &base;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ThreadInputStream::ThreadFunc()
|
ThreadInputStream::ThreadFunc()
|
||||||
{
|
{
|
||||||
FormatThreadName("input:%s", base.GetPlugin().name);
|
FormatThreadName("input:%s", GetPlugin().name);
|
||||||
|
|
||||||
Lock();
|
Lock();
|
||||||
if (!Open(postponed_error)) {
|
if (!Open(postponed_error)) {
|
||||||
base.cond.broadcast();
|
cond.broadcast();
|
||||||
Unlock();
|
Unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we're ready, tell it to our client */
|
/* we're ready, tell it to our client */
|
||||||
base.SetReady();
|
SetReady();
|
||||||
|
|
||||||
while (!close) {
|
while (!close) {
|
||||||
assert(!postponed_error.IsDefined());
|
assert(!postponed_error.IsDefined());
|
||||||
|
|
||||||
auto w = buffer->Write();
|
auto w = buffer->Write();
|
||||||
if (w.IsEmpty()) {
|
if (w.IsEmpty()) {
|
||||||
wake_cond.wait(base.mutex);
|
wake_cond.wait(mutex);
|
||||||
} else {
|
} else {
|
||||||
Unlock();
|
Unlock();
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ ThreadInputStream::ThreadFunc()
|
|||||||
size_t nbytes = Read(w.data, w.size, error);
|
size_t nbytes = Read(w.data, w.size, error);
|
||||||
|
|
||||||
Lock();
|
Lock();
|
||||||
base.cond.broadcast();
|
cond.broadcast();
|
||||||
|
|
||||||
if (nbytes == 0) {
|
if (nbytes == 0) {
|
||||||
eof = true;
|
eof = true;
|
||||||
@ -121,7 +121,8 @@ ThreadInputStream::Check2(Error &error)
|
|||||||
bool
|
bool
|
||||||
ThreadInputStream::Check(InputStream *is, Error &error)
|
ThreadInputStream::Check(InputStream *is, Error &error)
|
||||||
{
|
{
|
||||||
return Cast(is)->Check2(error);
|
ThreadInputStream &tis = *(ThreadInputStream *)is;
|
||||||
|
return tis.Check2(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
@ -133,11 +134,12 @@ ThreadInputStream::Available2()
|
|||||||
bool
|
bool
|
||||||
ThreadInputStream::Available(InputStream *is)
|
ThreadInputStream::Available(InputStream *is)
|
||||||
{
|
{
|
||||||
return Cast(is)->Available2();
|
ThreadInputStream &tis = *(ThreadInputStream *)is;
|
||||||
|
return tis.Available2();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
ThreadInputStream::Read2(void *ptr, size_t size, Error &error)
|
ThreadInputStream::Read2(void *ptr, size_t read_size, Error &error)
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
if (postponed_error.IsDefined()) {
|
if (postponed_error.IsDefined()) {
|
||||||
@ -147,18 +149,18 @@ ThreadInputStream::Read2(void *ptr, size_t size, Error &error)
|
|||||||
|
|
||||||
auto r = buffer->Read();
|
auto r = buffer->Read();
|
||||||
if (!r.IsEmpty()) {
|
if (!r.IsEmpty()) {
|
||||||
size_t nbytes = std::min(size, r.size);
|
size_t nbytes = std::min(read_size, r.size);
|
||||||
memcpy(ptr, r.data, nbytes);
|
memcpy(ptr, r.data, nbytes);
|
||||||
buffer->Consume(nbytes);
|
buffer->Consume(nbytes);
|
||||||
wake_cond.broadcast();
|
wake_cond.broadcast();
|
||||||
base.offset += nbytes;
|
offset += nbytes;
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eof)
|
if (eof)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
base.cond.wait(base.mutex);
|
cond.wait(mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +168,8 @@ size_t
|
|||||||
ThreadInputStream::Read(InputStream *is, void *ptr, size_t size,
|
ThreadInputStream::Read(InputStream *is, void *ptr, size_t size,
|
||||||
Error &error)
|
Error &error)
|
||||||
{
|
{
|
||||||
return Cast(is)->Read2(ptr, size, error);
|
ThreadInputStream &tis = *(ThreadInputStream *)is;
|
||||||
|
return tis.Read2(ptr, size, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -187,7 +190,8 @@ ThreadInputStream::Close2()
|
|||||||
void
|
void
|
||||||
ThreadInputStream::Close(InputStream *is)
|
ThreadInputStream::Close(InputStream *is)
|
||||||
{
|
{
|
||||||
Cast(is)->Close2();
|
ThreadInputStream &tis = *(ThreadInputStream *)is;
|
||||||
|
tis.Close2();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
@ -199,5 +203,6 @@ ThreadInputStream::IsEOF2()
|
|||||||
bool
|
bool
|
||||||
ThreadInputStream::IsEOF(InputStream *is)
|
ThreadInputStream::IsEOF(InputStream *is)
|
||||||
{
|
{
|
||||||
return Cast(is)->IsEOF2();
|
ThreadInputStream &tis = *(ThreadInputStream *)is;
|
||||||
|
return tis.IsEOF2();
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
#include "thread/Thread.hxx"
|
#include "thread/Thread.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "util/Cast.hxx"
|
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -40,9 +39,7 @@ template<typename T> class CircularBuffer;
|
|||||||
*
|
*
|
||||||
* This works only for "streams": unknown length, no seeking, no tags.
|
* This works only for "streams": unknown length, no seeking, no tags.
|
||||||
*/
|
*/
|
||||||
class ThreadInputStream {
|
class ThreadInputStream : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
Thread thread;
|
Thread thread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,7 +68,7 @@ public:
|
|||||||
ThreadInputStream(const InputPlugin &_plugin,
|
ThreadInputStream(const InputPlugin &_plugin,
|
||||||
const char *_uri, Mutex &_mutex, Cond &_cond,
|
const char *_uri, Mutex &_mutex, Cond &_cond,
|
||||||
size_t _buffer_size)
|
size_t _buffer_size)
|
||||||
:base(_plugin, _uri, _mutex, _cond),
|
:InputStream(_plugin, _uri, _mutex, _cond),
|
||||||
buffer_size(_buffer_size),
|
buffer_size(_buffer_size),
|
||||||
buffer(nullptr),
|
buffer(nullptr),
|
||||||
close(false), eof(false) {}
|
close(false), eof(false) {}
|
||||||
@ -86,24 +83,10 @@ public:
|
|||||||
InputStream *Start(Error &error);
|
InputStream *Start(Error &error);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Lock() {
|
void SetMimeType(const char *_mime) {
|
||||||
base.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unlock() {
|
|
||||||
base.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *GetURI() const {
|
|
||||||
assert(thread.IsInside());
|
assert(thread.IsInside());
|
||||||
|
|
||||||
return base.GetURI();
|
InputStream::SetMimeType(_mime);
|
||||||
}
|
|
||||||
|
|
||||||
void SetMimeType(const char *mime) {
|
|
||||||
assert(thread.IsInside());
|
|
||||||
|
|
||||||
base.SetMimeType(mime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* to be implemented by the plugin */
|
/* to be implemented by the plugin */
|
||||||
@ -145,20 +128,6 @@ protected:
|
|||||||
virtual void Cancel() {}
|
virtual void Cancel() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static constexpr ThreadInputStream *Cast(InputStream *is) {
|
|
||||||
return ContainerCast(is, ThreadInputStream, base);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ThreadFunc();
|
void ThreadFunc();
|
||||||
static void ThreadFunc(void *ctx);
|
static void ThreadFunc(void *ctx);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
#include "util/StringUtil.hxx"
|
#include "util/StringUtil.hxx"
|
||||||
#include "util/ReusableArray.hxx"
|
#include "util/ReusableArray.hxx"
|
||||||
#include "util/Cast.hxx"
|
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "event/MultiSocketMonitor.hxx"
|
#include "event/MultiSocketMonitor.hxx"
|
||||||
#include "event/DeferredMonitor.hxx"
|
#include "event/DeferredMonitor.hxx"
|
||||||
@ -64,8 +64,9 @@ static constexpr unsigned int default_rate = 44100; // cd quality
|
|||||||
*/
|
*/
|
||||||
static constexpr size_t read_buffer_size = 4096;
|
static constexpr size_t read_buffer_size = 4096;
|
||||||
|
|
||||||
class AlsaInputStream final : MultiSocketMonitor, DeferredMonitor {
|
class AlsaInputStream final
|
||||||
InputStream base;
|
: public InputStream,
|
||||||
|
MultiSocketMonitor, DeferredMonitor {
|
||||||
snd_pcm_t *capture_handle;
|
snd_pcm_t *capture_handle;
|
||||||
size_t frame_size;
|
size_t frame_size;
|
||||||
int frames_to_read;
|
int frames_to_read;
|
||||||
@ -81,23 +82,23 @@ class AlsaInputStream final : MultiSocketMonitor, DeferredMonitor {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AlsaInputStream(EventLoop &loop,
|
AlsaInputStream(EventLoop &loop,
|
||||||
const char *uri, Mutex &mutex, Cond &cond,
|
const char *_uri, Mutex &_mutex, Cond &_cond,
|
||||||
snd_pcm_t *_handle, int _frame_size)
|
snd_pcm_t *_handle, int _frame_size)
|
||||||
:MultiSocketMonitor(loop),
|
:InputStream(input_plugin_alsa, _uri, _mutex, _cond),
|
||||||
|
MultiSocketMonitor(loop),
|
||||||
DeferredMonitor(loop),
|
DeferredMonitor(loop),
|
||||||
base(input_plugin_alsa, uri, mutex, cond),
|
|
||||||
capture_handle(_handle),
|
capture_handle(_handle),
|
||||||
frame_size(_frame_size),
|
frame_size(_frame_size),
|
||||||
eof(false)
|
eof(false)
|
||||||
{
|
{
|
||||||
assert(uri != nullptr);
|
assert(_uri != nullptr);
|
||||||
assert(_handle != nullptr);
|
assert(_handle != nullptr);
|
||||||
|
|
||||||
/* this mime type forces use of the PcmDecoderPlugin.
|
/* this mime type forces use of the PcmDecoderPlugin.
|
||||||
Needs to be generalised when/if that decoder is
|
Needs to be generalised when/if that decoder is
|
||||||
updated to support other audio formats */
|
updated to support other audio formats */
|
||||||
base.SetMimeType("audio/x-mpd-cdda-pcm");
|
SetMimeType("audio/x-mpd-cdda-pcm");
|
||||||
base.SetReady();
|
InputStream::SetReady();
|
||||||
|
|
||||||
frames_to_read = read_buffer_size / frame_size;
|
frames_to_read = read_buffer_size / frame_size;
|
||||||
|
|
||||||
@ -115,19 +116,6 @@ public:
|
|||||||
static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond,
|
static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond,
|
||||||
Error &error);
|
Error &error);
|
||||||
|
|
||||||
#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static constexpr AlsaInputStream *Cast(InputStream *is) {
|
|
||||||
return ContainerCast(is, AlsaInputStream, base);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool Available() {
|
bool Available() {
|
||||||
if (snd_pcm_avail(capture_handle) > frames_to_read)
|
if (snd_pcm_avail(capture_handle) > frames_to_read)
|
||||||
return true;
|
return true;
|
||||||
@ -188,18 +176,17 @@ AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
int frame_size = snd_pcm_format_width(format) / 8 * channels;
|
int frame_size = snd_pcm_format_width(format) / 8 * channels;
|
||||||
AlsaInputStream *stream = new AlsaInputStream(io_thread_get(),
|
return new AlsaInputStream(io_thread_get(),
|
||||||
uri, mutex, cond,
|
uri, mutex, cond,
|
||||||
handle, frame_size);
|
handle, frame_size);
|
||||||
return &stream->base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
AlsaInputStream::Read(void *ptr, size_t size, Error &error)
|
AlsaInputStream::Read(void *ptr, size_t read_size, Error &error)
|
||||||
{
|
{
|
||||||
assert(ptr != nullptr);
|
assert(ptr != nullptr);
|
||||||
|
|
||||||
int num_frames = size / frame_size;
|
int num_frames = read_size / frame_size;
|
||||||
int ret;
|
int ret;
|
||||||
while ((ret = snd_pcm_readi(capture_handle, ptr, num_frames)) < 0) {
|
while ((ret = snd_pcm_readi(capture_handle, ptr, num_frames)) < 0) {
|
||||||
if (Recover(ret) < 0) {
|
if (Recover(ret) < 0) {
|
||||||
@ -211,7 +198,7 @@ AlsaInputStream::Read(void *ptr, size_t size, Error &error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t nbytes = ret * frame_size;
|
size_t nbytes = ret * frame_size;
|
||||||
base.offset += nbytes;
|
offset += nbytes;
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,9 +231,9 @@ AlsaInputStream::DispatchSockets()
|
|||||||
{
|
{
|
||||||
waiting = false;
|
waiting = false;
|
||||||
|
|
||||||
const ScopeLock protect(base.mutex);
|
const ScopeLock protect(mutex);
|
||||||
/* wake up the thread that is waiting for more data */
|
/* wake up the thread that is waiting for more data */
|
||||||
base.cond.broadcast();
|
cond.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int
|
inline int
|
||||||
@ -389,28 +376,28 @@ alsa_input_open(const char *uri, Mutex &mutex, Cond &cond, Error &error)
|
|||||||
static void
|
static void
|
||||||
alsa_input_close(InputStream *is)
|
alsa_input_close(InputStream *is)
|
||||||
{
|
{
|
||||||
AlsaInputStream *ais = AlsaInputStream::Cast(is);
|
AlsaInputStream *ais = (AlsaInputStream *)is;
|
||||||
delete ais;
|
delete ais;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
alsa_input_available(InputStream *is)
|
alsa_input_available(InputStream *is)
|
||||||
{
|
{
|
||||||
AlsaInputStream *ais = AlsaInputStream::Cast(is);
|
AlsaInputStream *ais = (AlsaInputStream *)is;
|
||||||
return ais->Available();
|
return ais->Available();
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
alsa_input_read(InputStream *is, void *ptr, size_t size, Error &error)
|
alsa_input_read(InputStream *is, void *ptr, size_t size, Error &error)
|
||||||
{
|
{
|
||||||
AlsaInputStream *ais = AlsaInputStream::Cast(is);
|
AlsaInputStream *ais = (AlsaInputStream *)is;
|
||||||
return ais->Read(ptr, size, error);
|
return ais->Read(ptr, size, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
alsa_input_eof(gcc_unused InputStream *is)
|
alsa_input_eof(gcc_unused InputStream *is)
|
||||||
{
|
{
|
||||||
AlsaInputStream *ais = AlsaInputStream::Cast(is);
|
AlsaInputStream *ais = (AlsaInputStream *)is;
|
||||||
return ais->IsEOF();
|
return ais->IsEOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,9 +50,7 @@
|
|||||||
|
|
||||||
#include <cdio/cd_types.h>
|
#include <cdio/cd_types.h>
|
||||||
|
|
||||||
struct CdioParanoiaInputStream {
|
struct CdioParanoiaInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
cdrom_drive_t *drv;
|
cdrom_drive_t *drv;
|
||||||
CdIo_t *cdio;
|
CdIo_t *cdio;
|
||||||
cdrom_paranoia_t *para;
|
cdrom_paranoia_t *para;
|
||||||
@ -65,9 +63,9 @@ struct CdioParanoiaInputStream {
|
|||||||
char buffer[CDIO_CD_FRAMESIZE_RAW];
|
char buffer[CDIO_CD_FRAMESIZE_RAW];
|
||||||
int buffer_lsn;
|
int buffer_lsn;
|
||||||
|
|
||||||
CdioParanoiaInputStream(const char *uri, Mutex &mutex, Cond &cond,
|
CdioParanoiaInputStream(const char *_uri, Mutex &_mutex, Cond &_cond,
|
||||||
int _trackno)
|
int _trackno)
|
||||||
:base(input_plugin_cdio_paranoia, uri, mutex, cond),
|
:InputStream(input_plugin_cdio_paranoia, _uri, _mutex, _cond),
|
||||||
drv(nullptr), cdio(nullptr), para(nullptr),
|
drv(nullptr), cdio(nullptr), para(nullptr),
|
||||||
trackno(_trackno)
|
trackno(_trackno)
|
||||||
{
|
{
|
||||||
@ -264,16 +262,16 @@ input_cdio_open(const char *uri,
|
|||||||
/* seek to beginning of the track */
|
/* seek to beginning of the track */
|
||||||
cdio_paranoia_seek(i->para, i->lsn_from, SEEK_SET);
|
cdio_paranoia_seek(i->para, i->lsn_from, SEEK_SET);
|
||||||
|
|
||||||
i->base.ready = true;
|
i->seekable = true;
|
||||||
i->base.seekable = true;
|
i->size = (i->lsn_to - i->lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW;
|
||||||
i->base.size = (i->lsn_to - i->lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW;
|
|
||||||
|
|
||||||
/* hack to make MPD select the "pcm" decoder plugin */
|
/* hack to make MPD select the "pcm" decoder plugin */
|
||||||
i->base.SetMimeType(reverse_endian
|
i->SetMimeType(reverse_endian
|
||||||
? "audio/x-mpd-cdda-pcm-reverse"
|
? "audio/x-mpd-cdda-pcm-reverse"
|
||||||
: "audio/x-mpd-cdda-pcm");
|
: "audio/x-mpd-cdda-pcm");
|
||||||
|
i->SetReady();
|
||||||
|
|
||||||
return &i->base;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -287,26 +285,26 @@ input_cdio_seek(InputStream *is,
|
|||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
break;
|
break;
|
||||||
case SEEK_CUR:
|
case SEEK_CUR:
|
||||||
offset += cis->base.offset;
|
offset += cis->offset;
|
||||||
break;
|
break;
|
||||||
case SEEK_END:
|
case SEEK_END:
|
||||||
offset += cis->base.size;
|
offset += cis->size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset < 0 || offset > cis->base.size) {
|
if (offset < 0 || offset > cis->size) {
|
||||||
error.Format(cdio_domain, "Invalid offset to seek %ld (%ld)",
|
error.Format(cdio_domain, "Invalid offset to seek %ld (%ld)",
|
||||||
(long int)offset, (long int)cis->base.size);
|
(long int)offset, (long int)cis->size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* simple case */
|
/* simple case */
|
||||||
if (offset == cis->base.offset)
|
if (offset == cis->offset)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* calculate current LSN */
|
/* calculate current LSN */
|
||||||
cis->lsn_relofs = offset / CDIO_CD_FRAMESIZE_RAW;
|
cis->lsn_relofs = offset / CDIO_CD_FRAMESIZE_RAW;
|
||||||
cis->base.offset = offset;
|
cis->offset = offset;
|
||||||
|
|
||||||
cdio_paranoia_seek(cis->para, cis->lsn_from + cis->lsn_relofs, SEEK_SET);
|
cdio_paranoia_seek(cis->para, cis->lsn_from + cis->lsn_relofs, SEEK_SET);
|
||||||
|
|
||||||
@ -360,7 +358,7 @@ input_cdio_read(InputStream *is, void *ptr, size_t length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//correct offset
|
//correct offset
|
||||||
diff = cis->base.offset - cis->lsn_relofs * CDIO_CD_FRAMESIZE_RAW;
|
diff = cis->offset - cis->lsn_relofs * CDIO_CD_FRAMESIZE_RAW;
|
||||||
|
|
||||||
assert(diff >= 0 && diff < CDIO_CD_FRAMESIZE_RAW);
|
assert(diff >= 0 && diff < CDIO_CD_FRAMESIZE_RAW);
|
||||||
|
|
||||||
@ -374,8 +372,8 @@ input_cdio_read(InputStream *is, void *ptr, size_t length,
|
|||||||
nbytes += len;
|
nbytes += len;
|
||||||
|
|
||||||
//update offset
|
//update offset
|
||||||
cis->base.offset += len;
|
cis->offset += len;
|
||||||
cis->lsn_relofs = cis->base.offset / CDIO_CD_FRAMESIZE_RAW;
|
cis->lsn_relofs = cis->offset / CDIO_CD_FRAMESIZE_RAW;
|
||||||
//update length
|
//update length
|
||||||
length -= len;
|
length -= len;
|
||||||
}
|
}
|
||||||
|
@ -67,9 +67,7 @@ static const size_t CURL_MAX_BUFFERED = 512 * 1024;
|
|||||||
*/
|
*/
|
||||||
static const size_t CURL_RESUME_AT = 384 * 1024;
|
static const size_t CURL_RESUME_AT = 384 * 1024;
|
||||||
|
|
||||||
struct CurlInputStream {
|
struct CurlInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
/* some buffers which were passed to libcurl, which we have
|
/* some buffers which were passed to libcurl, which we have
|
||||||
too free */
|
too free */
|
||||||
char range[32];
|
char range[32];
|
||||||
@ -106,9 +104,9 @@ struct CurlInputStream {
|
|||||||
|
|
||||||
Error postponed_error;
|
Error postponed_error;
|
||||||
|
|
||||||
CurlInputStream(const char *url, Mutex &mutex, Cond &cond,
|
CurlInputStream(const char *_url, Mutex &_mutex, Cond &_cond,
|
||||||
void *_buffer)
|
void *_buffer)
|
||||||
:base(input_plugin_curl, url, mutex, cond),
|
:InputStream(input_plugin_curl, _url, _mutex, _cond),
|
||||||
request_headers(nullptr),
|
request_headers(nullptr),
|
||||||
buffer((uint8_t *)_buffer, CURL_MAX_BUFFERED),
|
buffer((uint8_t *)_buffer, CURL_MAX_BUFFERED),
|
||||||
paused(false),
|
paused(false),
|
||||||
@ -486,7 +484,7 @@ CurlInputStream::RequestDone(CURLcode result, long status)
|
|||||||
|
|
||||||
FreeEasy();
|
FreeEasy();
|
||||||
|
|
||||||
const ScopeLock protect(base.mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
if (result != CURLE_OK) {
|
if (result != CURLE_OK) {
|
||||||
postponed_error.Format(curl_domain, result,
|
postponed_error.Format(curl_domain, result,
|
||||||
@ -497,7 +495,7 @@ CurlInputStream::RequestDone(CURLcode result, long status)
|
|||||||
status);
|
status);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.SetReady();
|
SetReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -688,7 +686,7 @@ inline bool
|
|||||||
CurlInputStream::FillBuffer(Error &error)
|
CurlInputStream::FillBuffer(Error &error)
|
||||||
{
|
{
|
||||||
while (easy != nullptr && buffer.IsEmpty())
|
while (easy != nullptr && buffer.IsEmpty())
|
||||||
base.cond.wait(base.mutex);
|
cond.wait(mutex);
|
||||||
|
|
||||||
if (postponed_error.IsDefined()) {
|
if (postponed_error.IsDefined()) {
|
||||||
error = std::move(postponed_error);
|
error = std::move(postponed_error);
|
||||||
@ -768,7 +766,7 @@ input_curl_available(InputStream *is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
CurlInputStream::Read(void *ptr, size_t size, Error &error)
|
CurlInputStream::Read(void *ptr, size_t read_size, Error &error)
|
||||||
{
|
{
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
|
||||||
@ -778,22 +776,22 @@ CurlInputStream::Read(void *ptr, size_t size, Error &error)
|
|||||||
if (!FillBuffer(error))
|
if (!FillBuffer(error))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nbytes = read_from_buffer(icy, buffer, ptr, size);
|
nbytes = read_from_buffer(icy, buffer, ptr, read_size);
|
||||||
} while (nbytes == 0);
|
} while (nbytes == 0);
|
||||||
|
|
||||||
if (icy.IsDefined())
|
if (icy.IsDefined())
|
||||||
CopyIcyTag();
|
CopyIcyTag();
|
||||||
|
|
||||||
base.offset += (InputPlugin::offset_type)nbytes;
|
offset += (InputPlugin::offset_type)nbytes;
|
||||||
|
|
||||||
if (paused && GetTotalBufferSize() < CURL_RESUME_AT) {
|
if (paused && GetTotalBufferSize() < CURL_RESUME_AT) {
|
||||||
base.mutex.unlock();
|
mutex.unlock();
|
||||||
|
|
||||||
BlockingCall(io_thread_get(), [this](){
|
BlockingCall(io_thread_get(), [this](){
|
||||||
Resume();
|
Resume();
|
||||||
});
|
});
|
||||||
|
|
||||||
base.mutex.lock();
|
mutex.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
@ -828,11 +826,11 @@ CurlInputStream::HeaderReceived(const char *name, std::string &&value)
|
|||||||
if (StringEqualsCaseASCII(name, "accept-ranges")) {
|
if (StringEqualsCaseASCII(name, "accept-ranges")) {
|
||||||
/* a stream with icy-metadata is not seekable */
|
/* a stream with icy-metadata is not seekable */
|
||||||
if (!icy.IsDefined())
|
if (!icy.IsDefined())
|
||||||
base.seekable = true;
|
seekable = true;
|
||||||
} else if (StringEqualsCaseASCII(name, "content-length")) {
|
} else if (StringEqualsCaseASCII(name, "content-length")) {
|
||||||
base.size = base.offset + ParseUint64(value.c_str());
|
size = offset + ParseUint64(value.c_str());
|
||||||
} else if (StringEqualsCaseASCII(name, "content-type")) {
|
} else if (StringEqualsCaseASCII(name, "content-type")) {
|
||||||
base.SetMimeType(std::move(value));
|
SetMimeType(std::move(value));
|
||||||
} else if (StringEqualsCaseASCII(name, "icy-name") ||
|
} else if (StringEqualsCaseASCII(name, "icy-name") ||
|
||||||
StringEqualsCaseASCII(name, "ice-name") ||
|
StringEqualsCaseASCII(name, "ice-name") ||
|
||||||
StringEqualsCaseASCII(name, "x-audiocast-name")) {
|
StringEqualsCaseASCII(name, "x-audiocast-name")) {
|
||||||
@ -856,7 +854,7 @@ CurlInputStream::HeaderReceived(const char *name, std::string &&value)
|
|||||||
|
|
||||||
/* a stream with icy-metadata is not
|
/* a stream with icy-metadata is not
|
||||||
seekable */
|
seekable */
|
||||||
base.seekable = false;
|
seekable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -898,13 +896,13 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
CurlInputStream::DataReceived(const void *ptr, size_t size)
|
CurlInputStream::DataReceived(const void *ptr, size_t received_size)
|
||||||
{
|
{
|
||||||
assert(size > 0);
|
assert(received_size > 0);
|
||||||
|
|
||||||
const ScopeLock protect(base.mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
if (size > buffer.GetSpace()) {
|
if (received_size > buffer.GetSpace()) {
|
||||||
paused = true;
|
paused = true;
|
||||||
return CURL_WRITEFUNC_PAUSE;
|
return CURL_WRITEFUNC_PAUSE;
|
||||||
}
|
}
|
||||||
@ -912,23 +910,23 @@ CurlInputStream::DataReceived(const void *ptr, size_t size)
|
|||||||
auto w = buffer.Write();
|
auto w = buffer.Write();
|
||||||
assert(!w.IsEmpty());
|
assert(!w.IsEmpty());
|
||||||
|
|
||||||
size_t nbytes = std::min(w.size, size);
|
size_t nbytes = std::min(w.size, received_size);
|
||||||
memcpy(w.data, ptr, nbytes);
|
memcpy(w.data, ptr, nbytes);
|
||||||
buffer.Append(nbytes);
|
buffer.Append(nbytes);
|
||||||
|
|
||||||
const size_t remaining = size - nbytes;
|
const size_t remaining = received_size - nbytes;
|
||||||
if (remaining > 0) {
|
if (remaining > 0) {
|
||||||
w = buffer.Write();
|
w = buffer.Write();
|
||||||
assert(!w.IsEmpty());
|
assert(!w.IsEmpty());
|
||||||
assert(w.size >= remaining);
|
assert(w.size >= remaining);
|
||||||
|
|
||||||
memcpy(w.data, (const uint8_t *)ptr + nbytes, remaining);
|
memcpy(w.data, (const uint8_t *)ptr + nbytes, remaining);
|
||||||
buffer.Append(size);
|
buffer.Append(received_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.ready = true;
|
ready = true;
|
||||||
base.cond.broadcast();
|
cond.broadcast();
|
||||||
return size;
|
return received_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** called by curl when new data is available */
|
/** called by curl when new data is available */
|
||||||
@ -986,7 +984,7 @@ CurlInputStream::InitEasy(Error &error)
|
|||||||
curl_easy_setopt(easy, CURLOPT_PROXYUSERPWD, proxy_auth_str);
|
curl_easy_setopt(easy, CURLOPT_PROXYUSERPWD, proxy_auth_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, base.GetURI());
|
CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, GetURI());
|
||||||
if (code != CURLE_OK) {
|
if (code != CURLE_OK) {
|
||||||
error.Format(curl_domain, code,
|
error.Format(curl_domain, code,
|
||||||
"curl_easy_setopt() failed: %s",
|
"curl_easy_setopt() failed: %s",
|
||||||
@ -1003,16 +1001,16 @@ CurlInputStream::InitEasy(Error &error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
CurlInputStream::Seek(InputPlugin::offset_type offset, int whence,
|
CurlInputStream::Seek(InputPlugin::offset_type new_offset, int whence,
|
||||||
Error &error)
|
Error &error)
|
||||||
{
|
{
|
||||||
assert(base.ready);
|
assert(IsReady());
|
||||||
|
|
||||||
if (whence == SEEK_SET && offset == base.offset)
|
if (whence == SEEK_SET && new_offset == offset)
|
||||||
/* no-op */
|
/* no-op */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!base.seekable)
|
if (!IsSeekable())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* calculate the absolute offset */
|
/* calculate the absolute offset */
|
||||||
@ -1022,52 +1020,52 @@ CurlInputStream::Seek(InputPlugin::offset_type offset, int whence,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SEEK_CUR:
|
case SEEK_CUR:
|
||||||
offset += base.offset;
|
new_offset += offset;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEEK_END:
|
case SEEK_END:
|
||||||
if (base.size < 0)
|
if (size < 0)
|
||||||
/* stream size is not known */
|
/* stream size is not known */
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
offset += base.size;
|
new_offset += size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset < 0)
|
if (new_offset < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* check if we can fast-forward the buffer */
|
/* check if we can fast-forward the buffer */
|
||||||
|
|
||||||
while (offset > base.offset) {
|
while (new_offset > offset) {
|
||||||
auto r = buffer.Read();
|
auto r = buffer.Read();
|
||||||
if (r.IsEmpty())
|
if (r.IsEmpty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const size_t nbytes =
|
const size_t nbytes =
|
||||||
offset - base.offset < (InputPlugin::offset_type)r.size
|
new_offset - offset < (InputPlugin::offset_type)r.size
|
||||||
? offset - base.offset
|
? new_offset - offset
|
||||||
: r.size;
|
: r.size;
|
||||||
|
|
||||||
buffer.Consume(nbytes);
|
buffer.Consume(nbytes);
|
||||||
base.offset += nbytes;
|
offset += nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset == base.offset)
|
if (new_offset == offset)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* close the old connection and open a new one */
|
/* close the old connection and open a new one */
|
||||||
|
|
||||||
base.mutex.unlock();
|
mutex.unlock();
|
||||||
|
|
||||||
FreeEasyIndirect();
|
FreeEasyIndirect();
|
||||||
buffer.Clear();
|
buffer.Clear();
|
||||||
|
|
||||||
base.offset = offset;
|
offset = new_offset;
|
||||||
if (base.offset == base.size) {
|
if (offset == size) {
|
||||||
/* seek to EOF: simulate empty result; avoid
|
/* seek to EOF: simulate empty result; avoid
|
||||||
triggering a "416 Requested Range Not Satisfiable"
|
triggering a "416 Requested Range Not Satisfiable"
|
||||||
response */
|
response */
|
||||||
@ -1079,18 +1077,18 @@ CurlInputStream::Seek(InputPlugin::offset_type offset, int whence,
|
|||||||
|
|
||||||
/* send the "Range" header */
|
/* send the "Range" header */
|
||||||
|
|
||||||
if (base.offset > 0) {
|
if (offset > 0) {
|
||||||
sprintf(range, "%lld-", (long long)base.offset);
|
sprintf(range, "%lld-", (long long)offset);
|
||||||
curl_easy_setopt(easy, CURLOPT_RANGE, range);
|
curl_easy_setopt(easy, CURLOPT_RANGE, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.ready = false;
|
ready = false;
|
||||||
|
|
||||||
if (!input_curl_easy_add_indirect(this, error))
|
if (!input_curl_easy_add_indirect(this, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
base.mutex.lock();
|
mutex.lock();
|
||||||
base.WaitReady();
|
WaitReady();
|
||||||
|
|
||||||
if (postponed_error.IsDefined()) {
|
if (postponed_error.IsDefined()) {
|
||||||
error = std::move(postponed_error);
|
error = std::move(postponed_error);
|
||||||
@ -1127,7 +1125,7 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return &c->base;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static InputStream *
|
static InputStream *
|
||||||
|
@ -36,9 +36,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
class DespotifyInputStream {
|
class DespotifyInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
struct despotify_session *session;
|
struct despotify_session *session;
|
||||||
struct ds_track *track;
|
struct ds_track *track;
|
||||||
Tag tag;
|
Tag tag;
|
||||||
@ -46,11 +44,11 @@ class DespotifyInputStream {
|
|||||||
size_t len_available;
|
size_t len_available;
|
||||||
bool eof;
|
bool eof;
|
||||||
|
|
||||||
DespotifyInputStream(const char *uri,
|
DespotifyInputStream(const char *_uri,
|
||||||
Mutex &mutex, Cond &cond,
|
Mutex &_mutex, Cond &_cond,
|
||||||
despotify_session *_session,
|
despotify_session *_session,
|
||||||
ds_track *_track)
|
ds_track *_track)
|
||||||
:base(input_plugin_despotify, uri, mutex, cond),
|
:InputStream(input_plugin_despotify, _uri, _mutex, _cond),
|
||||||
session(_session), track(_track),
|
session(_session), track(_track),
|
||||||
tag(mpd_despotify_tag_from_track(*track)),
|
tag(mpd_despotify_tag_from_track(*track)),
|
||||||
len_available(0), eof(false) {
|
len_available(0), eof(false) {
|
||||||
@ -58,8 +56,8 @@ class DespotifyInputStream {
|
|||||||
memset(&pcm, 0, sizeof(pcm));
|
memset(&pcm, 0, sizeof(pcm));
|
||||||
|
|
||||||
/* Despotify outputs pcm data */
|
/* Despotify outputs pcm data */
|
||||||
base.SetMimeType("audio/x-mpd-cdda-pcm");
|
SetMimeType("audio/x-mpd-cdda-pcm");
|
||||||
base.SetReady();
|
SetReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -190,7 +188,7 @@ DespotifyInputStream::Open(const char *url,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ctx->base;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static InputStream *
|
static InputStream *
|
||||||
@ -200,16 +198,17 @@ input_despotify_open(const char *url, Mutex &mutex, Cond &cond, Error &error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
DespotifyInputStream::Read(void *ptr, size_t size, gcc_unused Error &error)
|
DespotifyInputStream::Read(void *ptr, size_t read_size,
|
||||||
|
gcc_unused Error &error)
|
||||||
{
|
{
|
||||||
if (len_available == 0)
|
if (len_available == 0)
|
||||||
FillBuffer();
|
FillBuffer();
|
||||||
|
|
||||||
size_t to_cpy = std::min(size, len_available);
|
size_t to_cpy = std::min(read_size, len_available);
|
||||||
memcpy(ptr, pcm.buf, to_cpy);
|
memcpy(ptr, pcm.buf, to_cpy);
|
||||||
len_available -= to_cpy;
|
len_available -= to_cpy;
|
||||||
|
|
||||||
base.offset += to_cpy;
|
offset += to_cpy;
|
||||||
|
|
||||||
return to_cpy;
|
return to_cpy;
|
||||||
}
|
}
|
||||||
|
@ -33,26 +33,24 @@ extern "C" {
|
|||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FfmpegInputStream {
|
struct FfmpegInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
AVIOContext *h;
|
AVIOContext *h;
|
||||||
|
|
||||||
bool eof;
|
bool eof;
|
||||||
|
|
||||||
FfmpegInputStream(const char *uri, Mutex &mutex, Cond &cond,
|
FfmpegInputStream(const char *_uri, Mutex &_mutex, Cond &_cond,
|
||||||
AVIOContext *_h)
|
AVIOContext *_h)
|
||||||
:base(input_plugin_ffmpeg, uri, mutex, cond),
|
:InputStream(input_plugin_ffmpeg, _uri, _mutex, _cond),
|
||||||
h(_h), eof(false) {
|
h(_h), eof(false) {
|
||||||
base.ready = true;
|
seekable = (h->seekable & AVIO_SEEKABLE_NORMAL) != 0;
|
||||||
base.seekable = (h->seekable & AVIO_SEEKABLE_NORMAL) != 0;
|
size = avio_size(h);
|
||||||
base.size = avio_size(h);
|
|
||||||
|
|
||||||
/* hack to make MPD select the "ffmpeg" decoder plugin
|
/* hack to make MPD select the "ffmpeg" decoder plugin
|
||||||
- since avio.h doesn't tell us the MIME type of the
|
- since avio.h doesn't tell us the MIME type of the
|
||||||
resource, we can't select a decoder plugin, but the
|
resource, we can't select a decoder plugin, but the
|
||||||
"ffmpeg" plugin is quite good at auto-detection */
|
"ffmpeg" plugin is quite good at auto-detection */
|
||||||
base.SetMimeType("audio/x-mpd-ffmpeg");
|
SetMimeType("audio/x-mpd-ffmpeg");
|
||||||
|
SetReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
~FfmpegInputStream() {
|
~FfmpegInputStream() {
|
||||||
@ -105,8 +103,7 @@ input_ffmpeg_open(const char *uri,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *i = new FfmpegInputStream(uri, mutex, cond, h);
|
return new FfmpegInputStream(uri, mutex, cond, h);
|
||||||
return &i->base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
|
@ -33,18 +33,16 @@
|
|||||||
|
|
||||||
static constexpr Domain file_domain("file");
|
static constexpr Domain file_domain("file");
|
||||||
|
|
||||||
struct FileInputStream {
|
struct FileInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
FileInputStream(const char *path, int _fd, off_t size,
|
FileInputStream(const char *path, int _fd, off_t _size,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &_mutex, Cond &_cond)
|
||||||
:base(input_plugin_file, path, mutex, cond),
|
:InputStream(input_plugin_file, path, _mutex, _cond),
|
||||||
fd(_fd) {
|
fd(_fd) {
|
||||||
base.size = size;
|
size = _size;
|
||||||
base.seekable = true;
|
seekable = true;
|
||||||
base.SetReady();
|
SetReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
~FileInputStream() {
|
~FileInputStream() {
|
||||||
@ -88,9 +86,7 @@ input_file_open(const char *filename,
|
|||||||
posix_fadvise(fd, (off_t)0, st.st_size, POSIX_FADV_SEQUENTIAL);
|
posix_fadvise(fd, (off_t)0, st.st_size, POSIX_FADV_SEQUENTIAL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FileInputStream *fis = new FileInputStream(filename, fd, st.st_size,
|
return new FileInputStream(filename, fd, st.st_size, mutex, cond);
|
||||||
mutex, cond);
|
|
||||||
return &fis->base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -33,8 +33,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, Cond &_cond)
|
||||||
:ThreadInputStream(input_plugin_mms, uri, mutex, cond,
|
:ThreadInputStream(input_plugin_mms, _uri, _mutex, _cond,
|
||||||
MMS_BUFFER_SIZE) {
|
MMS_BUFFER_SIZE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,9 +89,9 @@ input_mms_open(const char *url,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
MmsInputStream::Read(void *ptr, size_t size, Error &error)
|
MmsInputStream::Read(void *ptr, size_t read_size, Error &error)
|
||||||
{
|
{
|
||||||
int nbytes = mmsx_read(nullptr, mms, (char *)ptr, size);
|
int nbytes = mmsx_read(nullptr, mms, (char *)ptr, read_size);
|
||||||
if (nbytes <= 0) {
|
if (nbytes <= 0) {
|
||||||
if (nbytes < 0)
|
if (nbytes < 0)
|
||||||
error.SetErrno("mmsx_read() failed");
|
error.SetErrno("mmsx_read() failed");
|
||||||
|
@ -33,22 +33,20 @@ extern "C" {
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
class NfsInputStream {
|
class NfsInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
nfs_context *ctx;
|
nfs_context *ctx;
|
||||||
nfsfh *fh;
|
nfsfh *fh;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NfsInputStream(const char *uri,
|
NfsInputStream(const char *_uri,
|
||||||
Mutex &mutex, Cond &cond,
|
Mutex &_mutex, Cond &_cond,
|
||||||
nfs_context *_ctx, nfsfh *_fh,
|
nfs_context *_ctx, nfsfh *_fh,
|
||||||
InputStream::offset_type size)
|
InputStream::offset_type _size)
|
||||||
:base(input_plugin_nfs, uri, mutex, cond),
|
:InputStream(input_plugin_nfs, _uri, _mutex, _cond),
|
||||||
ctx(_ctx), fh(_fh) {
|
ctx(_ctx), fh(_fh) {
|
||||||
base.ready = true;
|
seekable = true;
|
||||||
base.seekable = true;
|
size = _size;
|
||||||
base.size = size;
|
SetReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
~NfsInputStream() {
|
~NfsInputStream() {
|
||||||
@ -56,16 +54,12 @@ public:
|
|||||||
nfs_destroy_context(ctx);
|
nfs_destroy_context(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream *GetBase() {
|
|
||||||
return &base;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsEOF() const {
|
bool IsEOF() const {
|
||||||
return base.offset >= base.size;
|
return offset >= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size, Error &error) {
|
size_t Read(void *ptr, size_t read_size, Error &error) {
|
||||||
int nbytes = nfs_read(ctx, fh, size, (char *)ptr);
|
int nbytes = nfs_read(ctx, fh, read_size, (char *)ptr);
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
error.SetErrno(-nbytes, "nfs_read() failed");
|
error.SetErrno(-nbytes, "nfs_read() failed");
|
||||||
nbytes = 0;
|
nbytes = 0;
|
||||||
@ -74,15 +68,16 @@ public:
|
|||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Seek(InputStream::offset_type offset, int whence, Error &error) {
|
bool Seek(InputStream::offset_type new_offset, int whence, Error &error) {
|
||||||
uint64_t current_offset;
|
uint64_t current_offset;
|
||||||
int result = nfs_lseek(ctx, fh, offset, whence, ¤t_offset);
|
int result = nfs_lseek(ctx, fh, new_offset, whence,
|
||||||
|
¤t_offset);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
error.SetErrno(-result, "smbc_lseek() failed");
|
error.SetErrno(-result, "smbc_lseek() failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.offset = current_offset;
|
offset = current_offset;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -150,8 +145,7 @@ input_nfs_open(const char *uri,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto is = new NfsInputStream(uri, mutex, cond, ctx, fh, st.st_size);
|
return new NfsInputStream(uri, mutex, cond, ctx, fh, st.st_size);
|
||||||
return is->GetBase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
|
@ -28,9 +28,7 @@
|
|||||||
|
|
||||||
extern const InputPlugin rewind_input_plugin;
|
extern const InputPlugin rewind_input_plugin;
|
||||||
|
|
||||||
class RewindInputStream {
|
class RewindInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
InputStream *input;
|
InputStream *input;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,8 +54,8 @@ class RewindInputStream {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
RewindInputStream(InputStream *_input)
|
RewindInputStream(InputStream *_input)
|
||||||
:base(rewind_input_plugin, _input->GetURI(),
|
:InputStream(rewind_input_plugin, _input->GetURI(),
|
||||||
_input->mutex, _input->cond),
|
_input->mutex, _input->cond),
|
||||||
input(_input), tail(0) {
|
input(_input), tail(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,10 +63,6 @@ public:
|
|||||||
input->Close();
|
input->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream *GetBase() {
|
|
||||||
return &base;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Check(Error &error) {
|
bool Check(Error &error) {
|
||||||
return input->Check(error);
|
return input->Check(error);
|
||||||
}
|
}
|
||||||
@ -100,7 +94,7 @@ private:
|
|||||||
* buffer contain more data for the next read operation?
|
* buffer contain more data for the next read operation?
|
||||||
*/
|
*/
|
||||||
bool ReadingFromBuffer() const {
|
bool ReadingFromBuffer() const {
|
||||||
return tail > 0 && base.offset < input->offset;
|
return tail > 0 && offset < input->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,21 +104,20 @@ private:
|
|||||||
* attributes.
|
* attributes.
|
||||||
*/
|
*/
|
||||||
void CopyAttributes() {
|
void CopyAttributes() {
|
||||||
InputStream *dest = &base;
|
|
||||||
const InputStream *src = input;
|
const InputStream *src = input;
|
||||||
|
|
||||||
assert(dest != src);
|
assert(src != this);
|
||||||
|
|
||||||
if (!dest->IsReady() && src->IsReady()) {
|
if (!IsReady() && src->IsReady()) {
|
||||||
if (src->HasMimeType())
|
if (src->HasMimeType())
|
||||||
dest->SetMimeType(src->GetMimeType());
|
SetMimeType(src->GetMimeType());
|
||||||
|
|
||||||
dest->size = src->GetSize();
|
size = src->GetSize();
|
||||||
dest->seekable = src->IsSeekable();
|
seekable = src->IsSeekable();
|
||||||
dest->SetReady();
|
SetReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
dest->offset = src->offset;
|
offset = src->offset;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -169,31 +162,31 @@ input_rewind_available(InputStream *is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
RewindInputStream::Read(void *ptr, size_t size, Error &error)
|
RewindInputStream::Read(void *ptr, size_t read_size, Error &error)
|
||||||
{
|
{
|
||||||
if (ReadingFromBuffer()) {
|
if (ReadingFromBuffer()) {
|
||||||
/* buffered read */
|
/* buffered read */
|
||||||
|
|
||||||
assert(head == (size_t)base.offset);
|
assert(head == (size_t)offset);
|
||||||
assert(tail == (size_t)input->offset);
|
assert(tail == (size_t)input->offset);
|
||||||
|
|
||||||
if (size > tail - head)
|
if (read_size > tail - head)
|
||||||
size = tail - head;
|
read_size = tail - head;
|
||||||
|
|
||||||
memcpy(ptr, buffer + head, size);
|
memcpy(ptr, buffer + head, read_size);
|
||||||
head += size;
|
head += read_size;
|
||||||
base.offset += size;
|
offset += read_size;
|
||||||
|
|
||||||
return size;
|
return read_size;
|
||||||
} else {
|
} else {
|
||||||
/* pass method call to underlying stream */
|
/* pass method call to underlying stream */
|
||||||
|
|
||||||
size_t nbytes = input->Read(ptr, size, error);
|
size_t nbytes = input->Read(ptr, read_size, error);
|
||||||
|
|
||||||
if (input->offset > (InputPlugin::offset_type)sizeof(buffer))
|
if (input->offset > (InputPlugin::offset_type)sizeof(buffer))
|
||||||
/* disable buffering */
|
/* disable buffering */
|
||||||
tail = 0;
|
tail = 0;
|
||||||
else if (tail == (size_t)base.offset) {
|
else if (tail == (size_t)offset) {
|
||||||
/* append to buffer */
|
/* append to buffer */
|
||||||
|
|
||||||
memcpy(buffer + tail, ptr, nbytes);
|
memcpy(buffer + tail, ptr, nbytes);
|
||||||
@ -226,25 +219,25 @@ input_rewind_eof(InputStream *is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
RewindInputStream::Seek(InputPlugin::offset_type offset, int whence,
|
RewindInputStream::Seek(InputPlugin::offset_type new_offset, int whence,
|
||||||
Error &error)
|
Error &error)
|
||||||
{
|
{
|
||||||
assert(base.IsReady());
|
assert(IsReady());
|
||||||
|
|
||||||
if (whence == SEEK_SET && tail > 0 &&
|
if (whence == SEEK_SET && tail > 0 &&
|
||||||
offset <= (InputPlugin::offset_type)tail) {
|
new_offset <= (InputPlugin::offset_type)tail) {
|
||||||
/* buffered seek */
|
/* buffered seek */
|
||||||
|
|
||||||
assert(!ReadingFromBuffer() ||
|
assert(!ReadingFromBuffer() ||
|
||||||
head == (size_t)base.offset);
|
head == (size_t)offset);
|
||||||
assert(tail == (size_t)input->offset);
|
assert(tail == (size_t)input->offset);
|
||||||
|
|
||||||
head = (size_t)offset;
|
head = (size_t)new_offset;
|
||||||
base.offset = offset;
|
offset = new_offset;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
bool success = input->Seek(offset, whence, error);
|
bool success = input->Seek(new_offset, whence, error);
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
|
|
||||||
/* disable the buffer, because input has left the
|
/* disable the buffer, because input has left the
|
||||||
@ -290,6 +283,5 @@ input_rewind_open(InputStream *is)
|
|||||||
/* seekable resources don't need this plugin */
|
/* seekable resources don't need this plugin */
|
||||||
return is;
|
return is;
|
||||||
|
|
||||||
RewindInputStream *c = new RewindInputStream(is);
|
return new RewindInputStream(is);
|
||||||
return c->GetBase();
|
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,19 @@
|
|||||||
|
|
||||||
#include <libsmbclient.h>
|
#include <libsmbclient.h>
|
||||||
|
|
||||||
class SmbclientInputStream {
|
class SmbclientInputStream final : public InputStream {
|
||||||
InputStream base;
|
|
||||||
|
|
||||||
SMBCCTX *ctx;
|
SMBCCTX *ctx;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SmbclientInputStream(const char *uri,
|
SmbclientInputStream(const char *_uri,
|
||||||
Mutex &mutex, Cond &cond,
|
Mutex &_mutex, Cond &_cond,
|
||||||
SMBCCTX *_ctx, int _fd, const struct stat &st)
|
SMBCCTX *_ctx, int _fd, const struct stat &st)
|
||||||
:base(input_plugin_smbclient, uri, mutex, cond),
|
:InputStream(input_plugin_smbclient, _uri, _mutex, _cond),
|
||||||
ctx(_ctx), fd(_fd) {
|
ctx(_ctx), fd(_fd) {
|
||||||
base.ready = true;
|
seekable = true;
|
||||||
base.seekable = true;
|
size = st.st_size;
|
||||||
base.size = st.st_size;
|
SetReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
~SmbclientInputStream() {
|
~SmbclientInputStream() {
|
||||||
@ -52,17 +50,13 @@ public:
|
|||||||
smbclient_mutex.unlock();
|
smbclient_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream *GetBase() {
|
|
||||||
return &base;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsEOF() const {
|
bool IsEOF() const {
|
||||||
return base.offset >= base.size;
|
return offset >= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size, Error &error) {
|
size_t Read(void *ptr, size_t read_size, Error &error) {
|
||||||
smbclient_mutex.lock();
|
smbclient_mutex.lock();
|
||||||
ssize_t nbytes = smbc_read(fd, ptr, size);
|
ssize_t nbytes = smbc_read(fd, ptr, read_size);
|
||||||
smbclient_mutex.unlock();
|
smbclient_mutex.unlock();
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
error.SetErrno("smbc_read() failed");
|
error.SetErrno("smbc_read() failed");
|
||||||
@ -72,16 +66,16 @@ public:
|
|||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Seek(InputStream::offset_type offset, int whence, Error &error) {
|
bool Seek(InputStream::offset_type new_offset, int whence, Error &error) {
|
||||||
smbclient_mutex.lock();
|
smbclient_mutex.lock();
|
||||||
off_t result = smbc_lseek(fd, offset, whence);
|
off_t result = smbc_lseek(fd, new_offset, whence);
|
||||||
smbclient_mutex.unlock();
|
smbclient_mutex.unlock();
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
error.SetErrno("smbc_lseek() failed");
|
error.SetErrno("smbc_lseek() failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.offset = result;
|
offset = result;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -144,8 +138,7 @@ input_smbclient_open(const char *uri,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s = new SmbclientInputStream(uri, mutex, cond, ctx, fd, st);
|
return new SmbclientInputStream(uri, mutex, cond, ctx, fd, st);
|
||||||
return s->GetBase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
|
Loading…
Reference in New Issue
Block a user