diff options
-rw-r--r-- | src/decode.c | 4 | ||||
-rw-r--r-- | src/inputPlugins/wavpack_plugin.c | 159 | ||||
-rw-r--r-- | src/inputStream_http.c | 48 |
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; |