aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/decode.c4
-rw-r--r--src/inputPlugins/wavpack_plugin.c159
-rw-r--r--src/inputStream_http.c48
3 files changed, 175 insertions, 36 deletions
diff --git a/src/decode.c b/src/decode.c
index fcda78a19..ee8d43d3e 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -301,13 +301,13 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
dc->state = DECODE_STATE_START;
dc->start = 0;
-
+#if 0 /* this code is moved to the http stuff */
while (!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0
&& !dc->stop) {
/* sleep so we don't consume 100% of the cpu */
my_usleep(1000);
}
-
+#endif
/* for http streams, seekable is determined in bufferInputStream */
dc->seekable = inStream.seekable;
diff --git a/src/inputPlugins/wavpack_plugin.c b/src/inputPlugins/wavpack_plugin.c
index 73795df94..1d056dcd7 100644
--- a/src/inputPlugins/wavpack_plugin.c
+++ b/src/inputPlugins/wavpack_plugin.c
@@ -58,9 +58,6 @@ static struct {
{ NULL, 0 }
};
-/* workaround for at least the last push_back_byte */
-static int last_byte = EOF;
-
/*
* This function has been borrowed from the tiny player found on
* wavpack.com. Modifications were required because mpd only handles
@@ -142,7 +139,12 @@ static void wavpack_decode(OutputBuffer *cb, DecoderControl *dc,
format_samples = format_samples_float;
else
format_samples = format_samples_int;
-
+/*
+ if ((WavpackGetMode(wpc) & MODE_WVC) == MODE_WVC)
+ ERROR("decoding WITH wvc!!!\n");
+ else
+ ERROR("decoding without wvc\n");
+*/
allsamples = WavpackGetNumSamples(wpc);
Bps = WavpackGetBytesPerSample(wpc);
@@ -157,6 +159,7 @@ static void wavpack_decode(OutputBuffer *cb, DecoderControl *dc,
dc->totalTime = (float)allsamples / dc->audioFormat.sampleRate;
dc->state = DECODE_STATE_DECODE;
+ dc->seekable = canseek;
position = 0;
@@ -331,49 +334,57 @@ static MpdTag *wavpack_tagdup(char *fname)
* mpd InputStream <=> WavpackStreamReader wrapper callbacks
*/
+/* This struct is needed for per-stream last_byte storage. */
+typedef struct {
+ InputStream *is;
+ /* Needed for push_back_byte() */
+ int last_byte;
+} InputStreamPlus;
+
static int32_t read_bytes(void *id, void *data, int32_t bcount)
{
+ InputStreamPlus *isp = (InputStreamPlus *)id;
uint8_t *buf = (uint8_t *)data;
int32_t i = 0;
- if (last_byte != EOF) {
- *buf++ = last_byte;
- last_byte = EOF;
+ if (isp->last_byte != EOF) {
+ *buf++ = isp->last_byte;
+ isp->last_byte = EOF;
--bcount;
++i;
}
- return i + readFromInputStream((InputStream *)id, buf, 1, bcount);
+ return i + readFromInputStream(isp->is, buf, 1, bcount);
}
static uint32_t get_pos(void *id)
{
- return ((InputStream *)id)->offset;
+ return ((InputStreamPlus *)id)->is->offset;
}
static int set_pos_abs(void *id, uint32_t pos)
{
- return seekInputStream((InputStream *)id, pos, SEEK_SET);
+ return seekInputStream(((InputStreamPlus *)id)->is, pos, SEEK_SET);
}
static int set_pos_rel(void *id, int32_t delta, int mode)
{
- return seekInputStream((InputStream *)id, delta, mode);
+ return seekInputStream(((InputStreamPlus *)id)->is, delta, mode);
}
static int push_back_byte(void *id, int c)
{
- last_byte = c;
+ ((InputStreamPlus *)id)->last_byte = c;
return 1;
}
static uint32_t get_length(void *id)
{
- return ((InputStream *)id)->size;
+ return ((InputStreamPlus *)id)->is->size;
}
static int can_seek(void *id)
{
- return (seekInputStream((InputStream *)id, 0, SEEK_SET) != -1);
+ return ((InputStreamPlus *)id)->is->seekable;
}
static WavpackStreamReader mpd_is_reader = {
@@ -387,6 +398,13 @@ static WavpackStreamReader mpd_is_reader = {
.write_bytes = NULL /* no need to write edited tags */
};
+static void
+initInputStreamPlus(InputStreamPlus *isp, InputStream *is)
+{
+ isp->is = is;
+ isp->last_byte = EOF;
+}
+
/*
* Tries to decode the specified stream, and gives true if managed to do it.
*/
@@ -394,53 +412,137 @@ static unsigned int wavpack_trydecode(InputStream *is)
{
char error[ERRORLEN];
WavpackContext *wpc;
+ InputStreamPlus isp;
- wpc = WavpackOpenFileInputEx(&mpd_is_reader, (void *)is, NULL, error,
+ initInputStreamPlus(&isp, is);
+ wpc = WavpackOpenFileInputEx(&mpd_is_reader, &isp, NULL, error,
OPEN_STREAMING, 0);
if (wpc == NULL)
return 0;
WavpackCloseFile(wpc);
/* Seek it back in order to play from the first byte. */
- seekInputStream(is, 0, SEEK_SET);
+ if (is->seekable)
+ seekInputStream(is, 0, SEEK_SET);
return 1;
}
/*
* Decodes a stream.
- * We cannot handle wvc files this way, use the wavpack_filedecode for that.
*/
static int wavpack_streamdecode(OutputBuffer *cb, DecoderControl *dc,
InputStream *is)
{
char error[ERRORLEN];
WavpackContext *wpc;
+ InputStream is_wvc;
+ int open_flags = OPEN_2CH_MAX | OPEN_NORMALIZE;
+ char *wvc_url = NULL;
+ int err;
+ InputStreamPlus isp, isp_wvc;
+ int canseek;
+
+ /* Try to find wvc */
+ do {
+ size_t len;
+ err = 1;
+
+ /*
+ * As we use dc->utf8url, this function will be bad for
+ * single files. utf8url is not absolute file path :\
+ */
+ if (dc->utf8url == NULL)
+ break;
+
+ len = strlen(dc->utf8url);
+ if (!len)
+ break;
+
+ wvc_url = (char *)xmalloc(len + 2);
+ if (wvc_url == NULL)
+ break;
- /*
- * wavpack_streamdecode is unable to use wvc :-(
- * If we know the original stream url, we would find out the wvc url...
- * This would require InputStream to store that.
- */
+ strncpy(wvc_url, dc->utf8url, len);
+ wvc_url[len] = 'c';
+ wvc_url[len + 1] = '\0';
- wpc = WavpackOpenFileInputEx(&mpd_is_reader, (void *)is, NULL, error,
- OPEN_2CH_MAX | OPEN_NORMALIZE, 15);
+ if (openInputStream(&is_wvc, wvc_url))
+ break;
+#if 0 /* this code is moved to http stuff */
+ /*
+ * And we try to buffer in order to get know
+ * about a possible 404.
+ */
+ for (;;) {
+ if (inputStreamAtEOF(&is_wvc))
+ /*
+ * EOF is reached even without
+ * reading a single byte...
+ * So, this is not good :\
+ */
+ break;
+
+ if (bufferInputStream(&is_wvc) >= 0) {
+ err = 0;
+ break;
+ }
+
+ /* Can this happen?: */
+ if (dc->stop)
+ break;
+
+ /* Save some CPU */
+ my_usleep(1000);
+
+ }
+ if (err) {
+ closeInputStream(&is_wvc);
+ break;
+ }
+#endif
+ err = 0;
+
+ } while (0);
+
+ canseek = can_seek(&isp);
+ if (wvc_url != NULL) {
+ if (err) {
+ free(wvc_url);
+ wvc_url = NULL;
+ } else {
+ initInputStreamPlus(&isp_wvc, &is_wvc);
+ open_flags |= OPEN_WVC;
+ if (!can_seek(&isp_wvc))
+ canseek = 0;
+ }
+ }
+
+ if (!canseek)
+ open_flags |= OPEN_STREAMING;
+
+ initInputStreamPlus(&isp, is);
+ wpc = WavpackOpenFileInputEx(&mpd_is_reader, &isp, &isp_wvc, error,
+ open_flags, 15);
if (wpc == NULL) {
ERROR("failed to open WavPack stream: %s\n", error);
return -1;
}
- wavpack_decode(cb, dc, wpc, can_seek(is), NULL);
+ wavpack_decode(cb, dc, wpc, canseek, NULL);
WavpackCloseFile(wpc);
+ if (wvc_url != NULL) {
+ closeInputStream(&is_wvc);
+ free(wvc_url);
+ }
closeInputStream(is); /* calling side doesn't do this in mpd 0.13.0 */
return 0;
}
/*
- * Decodes a file. This has the goods on wavpack_streamdecode that this
- * can handle wvc files.
+ * Decodes a file.
*/
static int wavpack_filedecode(OutputBuffer *cb, DecoderControl *dc, char *fname)
{
@@ -475,9 +577,10 @@ InputPlugin wavpackPlugin = {
"wavpack",
NULL,
NULL,
+ /* Disabled till the http seek bug is fixed. */
wavpack_trydecode,
wavpack_streamdecode,
- wavpack_filedecode, /* provides more functionality! (wvc) */
+ wavpack_filedecode,
wavpack_tagdup,
INPUT_PLUGIN_STREAM_FILE | INPUT_PLUGIN_STREAM_URL,
wavpackSuffixes,
diff --git a/src/inputStream_http.c b/src/inputStream_http.c
index a2b343c6f..f7bcbce0f 100644
--- a/src/inputStream_http.c
+++ b/src/inputStream_http.c
@@ -698,7 +698,16 @@ int inputStream_httpOpen(InputStream * inStream, char *url)
inStream->atEOFFunc = inputStream_httpAtEOF;
inStream->bufferFunc = inputStream_httpBuffer;
- return 0;
+ while (!inputStream_httpAtEOF(inStream)) {
+ if (inputStream_httpBuffer(inStream) >= 0) {
+ return 0;
+ }
+ /* sleep so we don't consume 100% of the cpu */
+ my_usleep(1000);
+ }
+
+ freeInputStreamHTTPData(data);
+ return -1;
}
int inputStream_httpSeek(InputStream * inStream, long offset, int whence)
@@ -721,15 +730,20 @@ int inputStream_httpSeek(InputStream * inStream, long offset, int whence)
default:
return -1;
}
-
data = (InputStreamHTTPData *)inStream->data;
close(data->sock);
data->connState = HTTP_CONN_STATE_REOPEN;
data->buflen = 0;
- inputStream_httpBuffer(inStream);
+ while (!inputStream_httpAtEOF(inStream)) {
+ if (inputStream_httpBuffer(inStream) >= 0) {
+ return 0;
+ }
+ /* sleep so we don't consume 100% of the cpu */
+ my_usleep(1000);
+ }
- return 0;
+ return -1;
}
static void parseIcyMetadata(InputStream * inStream, char *metadata, int size)
@@ -759,8 +773,12 @@ static void parseIcyMetadata(InputStream * inStream, char *metadata, int size)
free(temp);
}
-size_t inputStream_httpRead(InputStream * inStream, void *ptr, size_t size,
- size_t nmemb)
+/*
+ * This stuff can only handle max bufsize sized blocks in the good case.
+ * Good case means the buffer is full.
+ */
+static size_t inputStream_httpRead_(InputStream * inStream, void *ptr,
+ size_t size, size_t nmemb)
{
InputStreamHTTPData *data = (InputStreamHTTPData *) inStream->data;
long tosend = 0;
@@ -826,6 +844,24 @@ size_t inputStream_httpRead(InputStream * inStream, void *ptr, size_t size,
return tosend / size;
}
+/* wrapper for the previous function */
+size_t inputStream_httpRead(InputStream *inStream, void *ptr, size_t size,
+ size_t nmemb)
+{
+ size_t req = nmemb * size;
+ size_t got = 0;
+
+ while (req) {
+ size_t r = inputStream_httpRead_(inStream, ptr + got, 1, req);
+ got += r;
+ req -= r;
+ if (inputStream_httpAtEOF(inStream))
+ break;
+ }
+
+ return got / size;
+}
+
int inputStream_httpClose(InputStream * inStream)
{
InputStreamHTTPData *data = (InputStreamHTTPData *) inStream->data;