diff --git a/src/decoder/DecoderAPI.cxx b/src/decoder/DecoderAPI.cxx
index 555e5c89b..5c4822804 100644
--- a/src/decoder/DecoderAPI.cxx
+++ b/src/decoder/DecoderAPI.cxx
@@ -240,6 +240,38 @@ void decoder_seek_error(Decoder & decoder)
 	decoder_command_finished(decoder);
 }
 
+InputStream *
+decoder_open_uri(Decoder &decoder, const char *uri, Error &error)
+{
+	assert(decoder.dc.state == DecoderState::START ||
+	       decoder.dc.state == DecoderState::DECODE);
+
+	DecoderControl &dc = decoder.dc;
+	Mutex &mutex = dc.mutex;
+	Cond &cond = dc.cond;
+
+	InputStream *is = InputStream::Open(uri, mutex, cond, error);
+	if (is == nullptr)
+		return nullptr;
+
+	mutex.lock();
+	while (true) {
+		is->Update();
+		if (is->IsReady()) {
+			mutex.unlock();
+			return is;
+		}
+
+		if (dc.command == DecoderCommand::STOP) {
+			mutex.unlock();
+			delete is;
+			return nullptr;
+		}
+
+		cond.wait(mutex);
+	}
+}
+
 /**
  * Should be read operation be cancelled?  That is the case when the
  * player thread has sent a command such as "STOP".
diff --git a/src/decoder/DecoderAPI.hxx b/src/decoder/DecoderAPI.hxx
index 0a7b84371..c57a02e01 100644
--- a/src/decoder/DecoderAPI.hxx
+++ b/src/decoder/DecoderAPI.hxx
@@ -40,6 +40,8 @@
 
 // IWYU pragma: end_exports
 
+class Error;
+
 /**
  * Notify the player thread that it has finished initialization and
  * that it has read the song's meta data.
@@ -95,6 +97,14 @@ decoder_seek_where(Decoder &decoder);
 void
 decoder_seek_error(Decoder &decoder);
 
+/**
+ * Open a new #InputStream and wait until it's ready.  Can get
+ * cancelled by DecoderCommand::STOP (returns nullptr without setting
+ * #Error).
+ */
+InputStream *
+decoder_open_uri(Decoder &decoder, const char *uri, Error &error);
+
 /**
  * Blocking read from the input stream.
  *
diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx
index e47bcbb30..e14d93369 100644
--- a/src/decoder/plugins/WavpackDecoderPlugin.cxx
+++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx
@@ -440,7 +440,6 @@ wavpack_input_init(WavpackInput *isp, Decoder &decoder,
 
 static InputStream *
 wavpack_open_wvc(Decoder &decoder, const char *uri,
-		 Mutex &mutex, Cond &cond,
 		 WavpackInput *wpi)
 {
 	/*
@@ -452,28 +451,13 @@ wavpack_open_wvc(Decoder &decoder, const char *uri,
 
 	char *wvc_url = g_strconcat(uri, "c", nullptr);
 
-	InputStream *is_wvc = InputStream::Open(wvc_url, mutex, cond,
-						IgnoreError());
+	InputStream *is_wvc = decoder_open_uri(decoder, uri, IgnoreError());
 	g_free(wvc_url);
 
 	if (is_wvc == nullptr)
 		return nullptr;
 
-	/*
-	 * And we try to buffer in order to get know
-	 * about a possible 404 error.
-	 */
-	char first_byte;
-	size_t nbytes = decoder_read(decoder, *is_wvc,
-				     &first_byte, sizeof(first_byte));
-	if (nbytes == 0) {
-		delete is_wvc;
-		return nullptr;
-	}
-
-	/* push it back */
 	wavpack_input_init(wpi, decoder, *is_wvc);
-	wpi->last_byte = first_byte;
 	return is_wvc;
 }
 
@@ -488,7 +472,6 @@ wavpack_streamdecode(Decoder &decoder, InputStream &is)
 
 	WavpackInput isp_wvc;
 	InputStream *is_wvc = wavpack_open_wvc(decoder, is.GetURI(),
-					       is.mutex, is.cond,
 					       &isp_wvc);
 	if (is_wvc != nullptr) {
 		open_flags |= OPEN_WVC;
diff --git a/test/FakeDecoderAPI.cxx b/test/FakeDecoderAPI.cxx
index 155e7d5df..7aa24c4df 100644
--- a/test/FakeDecoderAPI.cxx
+++ b/test/FakeDecoderAPI.cxx
@@ -66,6 +66,12 @@ decoder_seek_error(gcc_unused Decoder &decoder)
 {
 }
 
+InputStream *
+decoder_open_uri(Decoder &decoder, const char *uri, Error &error)
+{
+	return InputStream::OpenReady(uri, decoder.mutex, decoder.cond, error);
+}
+
 size_t
 decoder_read(gcc_unused Decoder *decoder,
 	     InputStream &is,
diff --git a/test/FakeDecoderAPI.hxx b/test/FakeDecoderAPI.hxx
index 134e77117..6f1933977 100644
--- a/test/FakeDecoderAPI.hxx
+++ b/test/FakeDecoderAPI.hxx
@@ -21,8 +21,13 @@
 #define FAKE_DECODER_API_HXX
 
 #include "check.h"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
 
 struct Decoder {
+	Mutex mutex;
+	Cond cond;
+
 	bool initialized;
 
 	Decoder()
diff --git a/test/run_decoder.cxx b/test/run_decoder.cxx
index b1c739405..3980340cc 100644
--- a/test/run_decoder.cxx
+++ b/test/run_decoder.cxx
@@ -27,7 +27,6 @@
 #include "fs/Path.hxx"
 #include "AudioFormat.hxx"
 #include "util/Error.hxx"
-#include "thread/Cond.hxx"
 #include "Log.hxx"
 #include "stdbin.h"
 
@@ -77,11 +76,9 @@ int main(int argc, char **argv)
 	if (plugin->file_decode != nullptr) {
 		plugin->FileDecode(decoder, Path::FromFS(uri));
 	} else if (plugin->stream_decode != nullptr) {
-		Mutex mutex;
-		Cond cond;
-
 		InputStream *is =
-			InputStream::OpenReady(uri, mutex, cond, error);
+			InputStream::OpenReady(uri, decoder.mutex,
+					       decoder.cond, error);
 		if (is == NULL) {
 			if (error.IsDefined())
 				LogError(error);