Try to open the ogg vorbis callbacks as soon as possible rather
than waiting until the input buffer reaches the given initial buffer
size. If that fails, try again later when more data is available but
fail if the input buffer size is larger than the initial buffer size
and we can still not open the ov callbacks.
Also, if a hole was detected, likely because we started streaming
in the middle of the file, add an additional delay to avoid buffer
underruns.
size_t inbuf_len;
/** The number of bytes consumed from the input buffer. */
size_t converted;
size_t inbuf_len;
/** The number of bytes consumed from the input buffer. */
size_t converted;
+ /** When to start producing output. */
+ struct timeval stream_start;
};
static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource)
};
static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource)
pod->converted = 0;
if (!pod->vf) {
pod->converted = 0;
if (!pod->vf) {
- int ib = 1024 * conf->initial_buffer_arg; /* initial buffer */
if (*fn->fc->input_error < 0)
return *fn->fc->input_error;
if (*fn->fc->input_error < 0)
return *fn->fc->input_error;
- if (len < ib) {
- PARA_DEBUG_LOG("initial input buffer %zd/%d, "
- "waiting for more data\n", len, ib);
pod->vf = para_malloc(sizeof(struct OggVorbis_File));
PARA_NOTICE_LOG("input buffer: %zd, opening ov callbacks\n", len);
ret = ov_open_callbacks(fn, pod->vf,
NULL, /* no initial buffer */
0, /* no initial bytes */
ovc); /* the ov_open_callbacks */
pod->vf = para_malloc(sizeof(struct OggVorbis_File));
PARA_NOTICE_LOG("input buffer: %zd, opening ov callbacks\n", len);
ret = ov_open_callbacks(fn, pod->vf,
NULL, /* no initial buffer */
0, /* no initial bytes */
ovc); /* the ov_open_callbacks */
+ if (ret == OV_ENOTVORBIS) {
+ /* this might be due to the input buffer being too small */
+ int ib = 1024 * conf->initial_buffer_arg; /* initial buffer */
+ if (len < ib) {
+ PARA_INFO_LOG("initial input buffer %zd/%d, "
+ "waiting for more data\n", len, ib);
+ free(pod->vf);
+ pod->vf = NULL;
+ return 0;
+ }
+ return -E_OGGDEC_NOTVORBIS;
+ }
if (ret == OV_EREAD)
return -E_OGGDEC_READ;
if (ret == OV_EREAD)
return -E_OGGDEC_READ;
- if (ret == OV_ENOTVORBIS)
- return -E_OGGDEC_NOTVORBIS;
if (ret == OV_EVERSION)
return -E_OGGDEC_VERSION;
if (ret == OV_EBADHEADER)
if (ret == OV_EVERSION)
return -E_OGGDEC_VERSION;
if (ret == OV_EBADHEADER)
fn->fc->samplerate = ov_info(pod->vf, 0)->rate;
PARA_NOTICE_LOG("%d channels, %d Hz\n", fn->fc->channels,
fn->fc->samplerate);
fn->fc->samplerate = ov_info(pod->vf, 0)->rate;
PARA_NOTICE_LOG("%d channels, %d Hz\n", fn->fc->channels,
fn->fc->samplerate);
+ /* wait a bit to avoid buffer underruns */
+ tv_add(now, &(struct timeval){0, 500 * 1000}, &pod->stream_start);
+ return pod->converted;
+ }
+ if (tv_diff(now, &pod->stream_start, NULL) < 0) {
+ PARA_DEBUG_LOG("initial delay..\n");
+ return 0;
}
while (fn->loaded < fn->bufsize) {
int length = fn->bufsize - fn->loaded;
long read_ret = ov_read(pod->vf, fn->buf + fn->loaded, length,
ENDIAN, 2 /* 16 bit */, 1 /* signed */, NULL);
}
while (fn->loaded < fn->bufsize) {
int length = fn->bufsize - fn->loaded;
long read_ret = ov_read(pod->vf, fn->buf + fn->loaded, length,
ENDIAN, 2 /* 16 bit */, 1 /* signed */, NULL);
- if (read_ret == OV_HOLE || !read_ret)
+ if (read_ret == 0)
+ return pod->converted;
+ if (read_ret == OV_HOLE) {
+ if (!fn->loaded) {
+ PARA_INFO_LOG("hole, delaying playback\n");
+ tv_add(now, &(struct timeval){0, 500 * 1000}, &pod->stream_start);
+ }
if (read_ret < 0)
return -E_OGGDEC_BADLINK;
fn->loaded += read_ret;
if (read_ret < 0)
return -E_OGGDEC_BADLINK;
fn->loaded += read_ret;