buffering: Unusual cases when a handle ridx is briefly seeked ahead of widx need to be handled properly. In the best case, buffer useful would be wrong and in the worst, a packet audio move_handle delta would be quite incorrect, causing the handle to be moved too far.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29490 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2011-03-02 04:41:29 +00:00
parent b3bfc09852
commit 64647f3403

View file

@ -560,6 +560,17 @@ fill_buffer : Call buffer_handle for all handles that have data to buffer
These functions are used by the buffering thread to manage buffer space. These functions are used by the buffering thread to manage buffer space.
*/ */
static size_t handle_size_available(const struct memory_handle *h)
{
/* Obtain proper distances from data start */
size_t rd = ringbuf_sub(h->ridx, h->data);
size_t wr = ringbuf_sub(h->widx, h->data);
if (LIKELY(wr > rd))
return wr - rd;
return 0; /* ridx is ahead of or equal to widx at this time */
}
static void update_data_counters(struct data_counters *dc) static void update_data_counters(struct data_counters *dc)
{ {
@ -582,6 +593,8 @@ static void update_data_counters(struct data_counters *dc)
m = first_handle; m = first_handle;
while (m) { while (m) {
buffered += m->available; buffered += m->available;
/* wasted could come out larger than the buffer size if ridx's are
overlapping data ahead of their handles' buffered data */
wasted += ringbuf_sub(m->ridx, m->data); wasted += ringbuf_sub(m->ridx, m->data);
remaining += m->filerem; remaining += m->filerem;
@ -589,7 +602,7 @@ static void update_data_counters(struct data_counters *dc)
is_useful = true; is_useful = true;
if (is_useful) if (is_useful)
useful += ringbuf_sub(m->widx, m->ridx); useful += handle_size_available(m);
m = m->next; m = m->next;
} }
@ -795,7 +808,11 @@ static void shrink_handle(struct memory_handle *h)
} }
} else { } else {
/* only move the handle struct */ /* only move the handle struct */
delta = ringbuf_sub(h->ridx, h->data); size_t rd = ringbuf_sub(h->ridx, h->data);
size_t wr = ringbuf_sub(h->widx, h->data);
/* ridx could be ahead of widx on a mini rebuffer */
delta = MIN(rd, wr);
if (!move_handle(&h, &delta, 0, true)) if (!move_handle(&h, &delta, 0, true))
return; return;
@ -1245,18 +1262,6 @@ int bufadvance(int handle_id, off_t offset)
* actual amount of data available for reading. This function explicitly * actual amount of data available for reading. This function explicitly
* does not check the validity of the input handle. It does do range checks * does not check the validity of the input handle. It does do range checks
* on size and returns a valid (and explicit) amount of data for reading */ * on size and returns a valid (and explicit) amount of data for reading */
static size_t handle_size_available(const struct memory_handle *h)
{
/* Obtain proper distances from data start */
size_t rd = ringbuf_sub(h->ridx, h->data);
size_t wr = ringbuf_sub(h->widx, h->data);
if (LIKELY(wr > rd))
return wr - rd;
return 0; /* ridx is ahead of or equal to widx at this time */
}
static struct memory_handle *prep_bufdata(int handle_id, size_t *size, static struct memory_handle *prep_bufdata(int handle_id, size_t *size,
bool guardbuf_limit) bool guardbuf_limit)
{ {