aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/TagStream.cxx6
-rw-r--r--src/TagStream.hxx2
-rw-r--r--src/archive/ArchiveFile.hxx2
-rw-r--r--src/decoder/DecoderBuffer.hxx2
-rw-r--r--src/decoder/DecoderPlugin.hxx2
-rw-r--r--src/decoder/DecoderThread.cxx7
-rw-r--r--src/decoder/plugins/DsdLib.hxx2
-rw-r--r--src/decoder/plugins/FfmpegDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/FlacInput.hxx2
-rw-r--r--src/decoder/plugins/OggCodec.hxx2
-rw-r--r--src/decoder/plugins/OggUtil.hxx2
-rw-r--r--src/decoder/plugins/WavpackDecoderPlugin.cxx2
-rw-r--r--src/input/InputPlugin.hxx2
-rw-r--r--src/input/InputStream.cxx9
-rw-r--r--src/input/InputStream.hxx58
-rw-r--r--src/input/TextInputStream.hxx2
-rw-r--r--src/input/ThreadInputStream.cxx19
-rw-r--r--src/input/ThreadInputStream.hxx8
-rw-r--r--src/input/plugins/AlsaInputPlugin.cxx5
-rw-r--r--src/input/plugins/CdioParanoiaInputPlugin.cxx6
-rw-r--r--src/input/plugins/CurlInputPlugin.cxx11
-rw-r--r--src/input/plugins/DespotifyInputPlugin.cxx4
-rw-r--r--src/input/plugins/FfmpegInputPlugin.cxx2
-rw-r--r--src/input/plugins/FileInputPlugin.cxx4
-rw-r--r--src/input/plugins/RewindInputPlugin.cxx21
-rw-r--r--src/input/plugins/RewindInputPlugin.hxx2
-rw-r--r--src/lib/expat/ExpatParser.hxx2
-rw-r--r--src/playlist/CloseSongEnumerator.hxx2
-rw-r--r--src/playlist/PlaylistPlugin.hxx2
-rw-r--r--src/playlist/PlaylistRegistry.hxx2
30 files changed, 130 insertions, 68 deletions
diff --git a/src/TagStream.cxx b/src/TagStream.cxx
index b84166825..98cbe193b 100644
--- a/src/TagStream.cxx
+++ b/src/TagStream.cxx
@@ -44,10 +44,10 @@ CheckDecoderPlugin(const DecoderPlugin &plugin,
bool
tag_stream_scan(InputStream &is, const tag_handler &handler, void *ctx)
{
- assert(is.ready);
+ assert(is.IsReady());
- const char *const suffix = uri_get_suffix(is.uri.c_str());
- const char *const mime = is.mime.empty() ? nullptr : is.mime.c_str();
+ const char *const suffix = uri_get_suffix(is.GetURI());
+ const char *const mime = is.GetMimeType();
if (suffix == nullptr && mime == nullptr)
return false;
diff --git a/src/TagStream.hxx b/src/TagStream.hxx
index 2f93768ee..71dd71ff7 100644
--- a/src/TagStream.hxx
+++ b/src/TagStream.hxx
@@ -22,7 +22,7 @@
#include "check.h"
-struct InputStream;
+class InputStream;
struct tag_handler;
/**
diff --git a/src/archive/ArchiveFile.hxx b/src/archive/ArchiveFile.hxx
index 7d6c9e17c..473eef70b 100644
--- a/src/archive/ArchiveFile.hxx
+++ b/src/archive/ArchiveFile.hxx
@@ -25,7 +25,7 @@ class Cond;
class Error;
struct ArchivePlugin;
class ArchiveVisitor;
-struct InputStream;
+class InputStream;
class ArchiveFile {
public:
diff --git a/src/decoder/DecoderBuffer.hxx b/src/decoder/DecoderBuffer.hxx
index 4cadd7740..d6f303c36 100644
--- a/src/decoder/DecoderBuffer.hxx
+++ b/src/decoder/DecoderBuffer.hxx
@@ -32,7 +32,7 @@
struct DecoderBuffer;
struct Decoder;
-struct InputStream;
+class InputStream;
template<typename T> struct ConstBuffer;
diff --git a/src/decoder/DecoderPlugin.hxx b/src/decoder/DecoderPlugin.hxx
index fd255ffb8..dbf3db9aa 100644
--- a/src/decoder/DecoderPlugin.hxx
+++ b/src/decoder/DecoderPlugin.hxx
@@ -23,7 +23,7 @@
#include "Compiler.h"
struct config_param;
-struct InputStream;
+class InputStream;
struct tag_handler;
class Path;
diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx
index 37b45bd24..4dd3c215c 100644
--- a/src/decoder/DecoderThread.cxx
+++ b/src/decoder/DecoderThread.cxx
@@ -87,7 +87,7 @@ decoder_input_stream_open(DecoderControl &dc, const char *uri)
dc.Lock();
is->Update();
- while (!is->ready &&
+ while (!is->IsReady() &&
dc.command != DecoderCommand::STOP) {
dc.Wait();
@@ -114,7 +114,7 @@ decoder_stream_decode(const DecoderPlugin &plugin,
assert(plugin.stream_decode != nullptr);
assert(decoder.stream_tag == nullptr);
assert(decoder.decoder_tag == nullptr);
- assert(input_stream.ready);
+ assert(input_stream.IsReady());
assert(decoder.dc.state == DecoderState::START);
FormatDebug(decoder_thread_domain, "probing plugin %s", plugin.name);
@@ -179,7 +179,8 @@ decoder_check_plugin_mime(const DecoderPlugin &plugin, const InputStream &is)
{
assert(plugin.stream_decode != nullptr);
- return !is.mime.empty() && plugin.SupportsMimeType(is.mime.c_str());
+ const char *mime_type = is.GetMimeType();
+ return mime_type != nullptr && plugin.SupportsMimeType(mime_type);
}
gcc_pure
diff --git a/src/decoder/plugins/DsdLib.hxx b/src/decoder/plugins/DsdLib.hxx
index 4c5e83114..88a76d72a 100644
--- a/src/decoder/plugins/DsdLib.hxx
+++ b/src/decoder/plugins/DsdLib.hxx
@@ -27,7 +27,7 @@
#include <stdint.h>
struct Decoder;
-struct InputStream;
+class InputStream;
struct DsdId {
char value[4];
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 6310ea7fe..3a0fa7389 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -385,7 +385,7 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
AVProbeData avpd;
avpd.buf = buffer;
avpd.buf_size = nbytes;
- avpd.filename = is.uri.c_str();
+ avpd.filename = is.GetURI();
return av_probe_input_format(&avpd, true);
}
@@ -409,7 +409,7 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
//ffmpeg works with ours "fileops" helper
AVFormatContext *format_context = nullptr;
if (mpd_ffmpeg_open_input(&format_context, stream.io,
- input.uri.c_str(),
+ input.GetURI(),
input_format) != 0) {
LogError(ffmpeg_domain, "Open failed");
return;
@@ -558,7 +558,7 @@ ffmpeg_scan_stream(InputStream &is,
return false;
AVFormatContext *f = nullptr;
- if (mpd_ffmpeg_open_input(&f, stream.io, is.uri.c_str(),
+ if (mpd_ffmpeg_open_input(&f, stream.io, is.GetURI(),
input_format) != 0)
return false;
diff --git a/src/decoder/plugins/FlacInput.hxx b/src/decoder/plugins/FlacInput.hxx
index 30ed55fd0..427abccb4 100644
--- a/src/decoder/plugins/FlacInput.hxx
+++ b/src/decoder/plugins/FlacInput.hxx
@@ -23,7 +23,7 @@
#include <FLAC/stream_decoder.h>
struct Decoder;
-struct InputStream;
+class InputStream;
/**
* This class wraps an #InputStream in libFLAC stream decoder
diff --git a/src/decoder/plugins/OggCodec.hxx b/src/decoder/plugins/OggCodec.hxx
index 6643d85ad..3b096561c 100644
--- a/src/decoder/plugins/OggCodec.hxx
+++ b/src/decoder/plugins/OggCodec.hxx
@@ -25,7 +25,7 @@
#define MPD_OGG_CODEC_HXX
struct Decoder;
-struct InputStream;
+class InputStream;
enum ogg_codec {
OGG_CODEC_UNKNOWN,
diff --git a/src/decoder/plugins/OggUtil.hxx b/src/decoder/plugins/OggUtil.hxx
index 3289702a3..94c380ef4 100644
--- a/src/decoder/plugins/OggUtil.hxx
+++ b/src/decoder/plugins/OggUtil.hxx
@@ -26,7 +26,7 @@
#include <stddef.h>
-struct InputStream;
+class InputStream;
struct Decoder;
/**
diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx
index 27bede56c..070a913f2 100644
--- a/src/decoder/plugins/WavpackDecoderPlugin.cxx
+++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx
@@ -487,7 +487,7 @@ wavpack_streamdecode(Decoder &decoder, InputStream &is)
bool can_seek = is.seekable;
wavpack_input isp_wvc;
- InputStream *is_wvc = wavpack_open_wvc(decoder, is.uri.c_str(),
+ InputStream *is_wvc = wavpack_open_wvc(decoder, is.GetURI(),
is.mutex, is.cond,
&isp_wvc);
if (is_wvc != nullptr) {
diff --git a/src/input/InputPlugin.hxx b/src/input/InputPlugin.hxx
index 090c73df8..412ca4cf9 100644
--- a/src/input/InputPlugin.hxx
+++ b/src/input/InputPlugin.hxx
@@ -35,7 +35,7 @@
#endif
struct config_param;
-struct InputStream;
+class InputStream;
class Error;
struct Tag;
diff --git a/src/input/InputStream.cxx b/src/input/InputStream.cxx
index 0621437c4..d54eca643 100644
--- a/src/input/InputStream.cxx
+++ b/src/input/InputStream.cxx
@@ -93,6 +93,15 @@ InputStream::Update()
}
void
+InputStream::SetReady()
+{
+ assert(!ready);
+
+ ready = true;
+ cond.broadcast();
+}
+
+void
InputStream::WaitReady()
{
while (true) {
diff --git a/src/input/InputStream.hxx b/src/input/InputStream.hxx
index c66091687..65840ba27 100644
--- a/src/input/InputStream.hxx
+++ b/src/input/InputStream.hxx
@@ -34,9 +34,11 @@ class Error;
struct Tag;
struct InputPlugin;
-struct InputStream {
+class InputStream {
+public:
typedef int64_t offset_type;
+private:
/**
* the plugin which implements this input stream
*/
@@ -47,6 +49,7 @@ struct InputStream {
*/
std::string uri;
+public:
/**
* A mutex that protects the mutable attributes of this object
* and its implementation. It must be locked before calling
@@ -83,16 +86,19 @@ struct InputStream {
*/
offset_type size;
+public:
/**
* the current offset within the stream
*/
offset_type offset;
+private:
/**
* the MIME content type of the resource, or empty if unknown.
*/
std::string mime;
+public:
InputStream(const InputPlugin &_plugin,
const char *_uri, Mutex &_mutex, Cond &_cond)
:plugin(_plugin), uri(_uri),
@@ -134,6 +140,19 @@ struct InputStream {
*/
void Close();
+ const InputPlugin &GetPlugin() const {
+ return plugin;
+ }
+
+ /**
+ * The absolute URI which was used to open this stream.
+ *
+ * No lock necessary for this method.
+ */
+ const char *GetURI() const {
+ return uri.c_str();
+ }
+
void Lock() {
mutex.lock();
}
@@ -155,11 +174,18 @@ struct InputStream {
*/
void Update();
+ void SetReady();
+
/**
- * Wait until the stream becomes ready.
+ * Return whether the stream is ready for reading and whether
+ * the other attributes in this struct are valid.
*
* The caller must lock the mutex.
*/
+ bool IsReady() const {
+ return ready;
+ }
+
void WaitReady();
/**
@@ -169,6 +195,13 @@ struct InputStream {
void LockWaitReady();
gcc_pure
+ bool HasMimeType() const {
+ assert(ready);
+
+ return !mime.empty();
+ }
+
+ gcc_pure
const char *GetMimeType() const {
assert(ready);
@@ -176,6 +209,19 @@ struct InputStream {
}
gcc_nonnull_all
+ void SetMimeType(const char *_mime) {
+ assert(!ready);
+
+ mime = _mime;
+ }
+
+ void SetMimeType(std::string &&_mime) {
+ assert(!ready);
+
+ mime = std::move(_mime);
+ }
+
+ gcc_nonnull_all
void OverrideMimeType(const char *_mime) {
assert(ready);
@@ -189,6 +235,14 @@ struct InputStream {
return size;
}
+ void AddOffset(offset_type delta) {
+ assert(ready);
+ assert(offset >= 0);
+ assert(delta >= 0);
+
+ offset += delta;
+ }
+
gcc_pure
offset_type GetOffset() const {
assert(ready);
diff --git a/src/input/TextInputStream.hxx b/src/input/TextInputStream.hxx
index 86ae16e41..c67423da1 100644
--- a/src/input/TextInputStream.hxx
+++ b/src/input/TextInputStream.hxx
@@ -24,7 +24,7 @@
#include <string>
-struct InputStream;
+class InputStream;
class TextInputStream {
InputStream &is;
diff --git a/src/input/ThreadInputStream.cxx b/src/input/ThreadInputStream.cxx
index 5271171ef..fde9bd08e 100644
--- a/src/input/ThreadInputStream.cxx
+++ b/src/input/ThreadInputStream.cxx
@@ -58,18 +58,17 @@ ThreadInputStream::Start(Error &error)
inline void
ThreadInputStream::ThreadFunc()
{
- FormatThreadName("input:%s", base.plugin.name);
+ FormatThreadName("input:%s", base.GetPlugin().name);
- base.mutex.lock();
+ Lock();
if (!Open(postponed_error)) {
base.cond.broadcast();
- base.mutex.unlock();
+ Unlock();
return;
}
/* we're ready, tell it to our client */
- base.ready = true;
- base.cond.broadcast();
+ base.SetReady();
while (!close) {
assert(!postponed_error.IsDefined());
@@ -78,12 +77,12 @@ ThreadInputStream::ThreadFunc()
if (w.IsEmpty()) {
wake_cond.wait(base.mutex);
} else {
- base.mutex.unlock();
+ Unlock();
Error error;
size_t nbytes = Read(w.data, w.size, error);
- base.mutex.lock();
+ Lock();
base.cond.broadcast();
if (nbytes == 0) {
@@ -96,7 +95,7 @@ ThreadInputStream::ThreadFunc()
}
}
- base.mutex.unlock();
+ Unlock();
Close();
}
@@ -173,10 +172,10 @@ ThreadInputStream::Read(InputStream *is, void *ptr, size_t size,
inline void
ThreadInputStream::Close2()
{
- base.mutex.lock();
+ Lock();
close = true;
wake_cond.signal();
- base.mutex.unlock();
+ Unlock();
Cancel();
diff --git a/src/input/ThreadInputStream.hxx b/src/input/ThreadInputStream.hxx
index 01428d717..8bae93a05 100644
--- a/src/input/ThreadInputStream.hxx
+++ b/src/input/ThreadInputStream.hxx
@@ -87,23 +87,23 @@ public:
protected:
void Lock() {
- base.mutex.lock();
+ base.Lock();
}
void Unlock() {
- base.mutex.unlock();
+ base.Unlock();
}
const char *GetURI() const {
assert(thread.IsInside());
- return base.uri.c_str();
+ return base.GetURI();
}
void SetMimeType(const char *mime) {
assert(thread.IsInside());
- base.mime = mime;
+ base.SetMimeType(mime);
}
/* to be implemented by the plugin */
diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx
index eae06ba6c..129219c01 100644
--- a/src/input/plugins/AlsaInputPlugin.cxx
+++ b/src/input/plugins/AlsaInputPlugin.cxx
@@ -96,8 +96,9 @@ public:
/* this mime type forces use of the PcmDecoderPlugin.
Needs to be generalised when/if that decoder is
updated to support other audio formats */
- base.mime = "audio/x-mpd-cdda-pcm";
- base.ready = true;
+ base.SetMimeType("audio/x-mpd-cdda-pcm");
+ base.SetReady();
+
frames_to_read = read_buffer_size / frame_size;
snd_pcm_start(capture_handle);
diff --git a/src/input/plugins/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx
index 767b2600f..5b4ce2ec6 100644
--- a/src/input/plugins/CdioParanoiaInputPlugin.cxx
+++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx
@@ -269,9 +269,9 @@ input_cdio_open(const char *uri,
i->base.size = (i->lsn_to - i->lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW;
/* hack to make MPD select the "pcm" decoder plugin */
- i->base.mime = reverse_endian
- ? "audio/x-mpd-cdda-pcm-reverse"
- : "audio/x-mpd-cdda-pcm";
+ i->base.SetMimeType(reverse_endian
+ ? "audio/x-mpd-cdda-pcm-reverse"
+ : "audio/x-mpd-cdda-pcm");
return &i->base;
}
diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx
index 37509e998..5f8b9150a 100644
--- a/src/input/plugins/CurlInputPlugin.cxx
+++ b/src/input/plugins/CurlInputPlugin.cxx
@@ -497,8 +497,7 @@ CurlInputStream::RequestDone(CURLcode result, long status)
status);
}
- base.ready = true;
- base.cond.broadcast();
+ base.SetReady();
}
static void
@@ -833,7 +832,7 @@ CurlInputStream::HeaderReceived(const char *name, std::string &&value)
} else if (StringEqualsCaseASCII(name, "content-length")) {
base.size = base.offset + ParseUint64(value.c_str());
} else if (StringEqualsCaseASCII(name, "content-type")) {
- base.mime = std::move(value);
+ base.SetMimeType(std::move(value));
} else if (StringEqualsCaseASCII(name, "icy-name") ||
StringEqualsCaseASCII(name, "ice-name") ||
StringEqualsCaseASCII(name, "x-audiocast-name")) {
@@ -987,7 +986,7 @@ CurlInputStream::InitEasy(Error &error)
curl_easy_setopt(easy, CURLOPT_PROXYUSERPWD, proxy_auth_str);
}
- CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, base.uri.c_str());
+ CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, base.GetURI());
if (code != CURLE_OK) {
error.Format(curl_domain, code,
"curl_easy_setopt() failed: %s",
@@ -1091,9 +1090,7 @@ CurlInputStream::Seek(InputPlugin::offset_type offset, int whence,
return false;
base.mutex.lock();
-
- while (!base.ready)
- base.cond.wait(base.mutex);
+ base.WaitReady();
if (postponed_error.IsDefined()) {
error = std::move(postponed_error);
diff --git a/src/input/plugins/DespotifyInputPlugin.cxx b/src/input/plugins/DespotifyInputPlugin.cxx
index 152fda95f..702ebc132 100644
--- a/src/input/plugins/DespotifyInputPlugin.cxx
+++ b/src/input/plugins/DespotifyInputPlugin.cxx
@@ -58,8 +58,8 @@ class DespotifyInputStream {
memset(&pcm, 0, sizeof(pcm));
/* Despotify outputs pcm data */
- base.mime = "audio/x-mpd-cdda-pcm";
- base.ready = true;
+ base.SetMimeType("audio/x-mpd-cdda-pcm");
+ base.SetReady();
}
public:
diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx
index dab4b59fb..d06d4705a 100644
--- a/src/input/plugins/FfmpegInputPlugin.cxx
+++ b/src/input/plugins/FfmpegInputPlugin.cxx
@@ -52,7 +52,7 @@ struct FfmpegInputStream {
- since avio.h doesn't tell us the MIME type of the
resource, we can't select a decoder plugin, but the
"ffmpeg" plugin is quite good at auto-detection */
- base.mime = "audio/x-mpd-ffmpeg";
+ base.SetMimeType("audio/x-mpd-ffmpeg");
}
~FfmpegInputStream() {
diff --git a/src/input/plugins/FileInputPlugin.cxx b/src/input/plugins/FileInputPlugin.cxx
index 780e93263..49dc3df7e 100644
--- a/src/input/plugins/FileInputPlugin.cxx
+++ b/src/input/plugins/FileInputPlugin.cxx
@@ -44,7 +44,7 @@ struct FileInputStream {
fd(_fd) {
base.size = size;
base.seekable = true;
- base.ready = true;
+ base.SetReady();
}
~FileInputStream() {
@@ -138,7 +138,7 @@ input_file_close(InputStream *is)
static bool
input_file_eof(InputStream *is)
{
- return is->offset >= is->size;
+ return is->GetOffset() >= is->GetSize();
}
const InputPlugin input_plugin_file = {
diff --git a/src/input/plugins/RewindInputPlugin.cxx b/src/input/plugins/RewindInputPlugin.cxx
index 1a930ac53..1cc146d3f 100644
--- a/src/input/plugins/RewindInputPlugin.cxx
+++ b/src/input/plugins/RewindInputPlugin.cxx
@@ -55,7 +55,7 @@ struct RewindInputStream {
char buffer[64 * 1024];
RewindInputStream(InputStream *_input)
- :base(rewind_input_plugin, _input->uri.c_str(),
+ :base(rewind_input_plugin, _input->GetURI(),
_input->mutex, _input->cond),
input(_input), tail(0) {
}
@@ -84,15 +84,16 @@ struct RewindInputStream {
assert(dest != src);
- bool dest_ready = dest->ready;
+ if (!dest->IsReady() && src->IsReady()) {
+ if (src->HasMimeType())
+ dest->SetMimeType(src->GetMimeType());
- dest->ready = src->ready;
- dest->seekable = src->seekable;
- dest->size = src->size;
- dest->offset = src->offset;
+ dest->size = src->GetSize();
+ dest->seekable = src->IsSeekable();
+ dest->SetReady();
+ }
- if (!dest_ready && src->ready)
- dest->mime = src->mime;
+ dest->offset = src->offset;
}
};
@@ -195,7 +196,7 @@ input_rewind_seek(InputStream *is, InputPlugin::offset_type offset,
{
RewindInputStream *r = (RewindInputStream *)is;
- assert(is->ready);
+ assert(is->IsReady());
if (whence == SEEK_SET && r->tail > 0 &&
offset <= (InputPlugin::offset_type)r->tail) {
@@ -242,7 +243,7 @@ input_rewind_open(InputStream *is)
assert(is != nullptr);
assert(is->offset == 0);
- if (is->seekable)
+ if (is->IsReady() && is->IsSeekable())
/* seekable resources don't need this plugin */
return is;
diff --git a/src/input/plugins/RewindInputPlugin.hxx b/src/input/plugins/RewindInputPlugin.hxx
index f19705154..56b01b585 100644
--- a/src/input/plugins/RewindInputPlugin.hxx
+++ b/src/input/plugins/RewindInputPlugin.hxx
@@ -29,7 +29,7 @@
#include "check.h"
-struct InputStream;
+class InputStream;
InputStream *
input_rewind_open(InputStream *is);
diff --git a/src/lib/expat/ExpatParser.hxx b/src/lib/expat/ExpatParser.hxx
index d57a85533..9d2ac65e5 100644
--- a/src/lib/expat/ExpatParser.hxx
+++ b/src/lib/expat/ExpatParser.hxx
@@ -25,7 +25,7 @@
#include <expat.h>
-struct InputStream;
+class InputStream;
class Error;
class ExpatParser final {
diff --git a/src/playlist/CloseSongEnumerator.hxx b/src/playlist/CloseSongEnumerator.hxx
index 5a95cc28b..17f015394 100644
--- a/src/playlist/CloseSongEnumerator.hxx
+++ b/src/playlist/CloseSongEnumerator.hxx
@@ -23,7 +23,7 @@
#include "SongEnumerator.hxx"
#include "Compiler.h"
-struct InputStream;
+class InputStream;
/**
* A #SongEnumerator wrapper that closes an #InputStream automatically
diff --git a/src/playlist/PlaylistPlugin.hxx b/src/playlist/PlaylistPlugin.hxx
index d3c44f1f4..fd779ad8d 100644
--- a/src/playlist/PlaylistPlugin.hxx
+++ b/src/playlist/PlaylistPlugin.hxx
@@ -21,7 +21,7 @@
#define MPD_PLAYLIST_PLUGIN_HXX
struct config_param;
-struct InputStream;
+class InputStream;
struct Tag;
class Mutex;
class Cond;
diff --git a/src/playlist/PlaylistRegistry.hxx b/src/playlist/PlaylistRegistry.hxx
index f1833b925..7ce559baa 100644
--- a/src/playlist/PlaylistRegistry.hxx
+++ b/src/playlist/PlaylistRegistry.hxx
@@ -23,7 +23,7 @@
class Mutex;
class Cond;
class SongEnumerator;
-struct InputStream;
+class InputStream;
extern const struct playlist_plugin *const playlist_plugins[];