Skip to content

Commit 8ffb4af

Browse files
committed
fix: enforce configured audio buffer max fill
1 parent 3d2621c commit 8ffb4af

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

src/audio-buffer.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ static int fill_ms_unlocked(const struct audio_buffer *buf)
3636
return (int)(samples * 1000 / buf->sample_rate);
3737
}
3838

39+
static size_t max_fill_bytes_unlocked(const struct audio_buffer *buf)
40+
{
41+
size_t max_fill = ms_to_bytes(buf, buf->max_ms);
42+
if (max_fill == 0 || max_fill > buf->capacity)
43+
max_fill = buf->capacity;
44+
return max_fill;
45+
}
46+
3947
/* Write raw bytes to the ring buffer (no PTS tracking). */
4048
static size_t ring_write(struct audio_buffer *buf, const uint8_t *samples,
4149
size_t bytes)
@@ -100,6 +108,53 @@ static void skip_oldest_chunk_locked(struct audio_buffer *buf)
100108
buf->chunk_count--;
101109
}
102110

111+
static void drop_oldest_bytes_locked(struct audio_buffer *buf, size_t bytes)
112+
{
113+
if (!buf->data || bytes == 0 || buf->fill == 0)
114+
return;
115+
116+
if (bytes > buf->fill)
117+
bytes = buf->fill;
118+
119+
buf->tail = (buf->tail + bytes) % buf->capacity;
120+
buf->fill -= bytes;
121+
}
122+
123+
static size_t trim_incoming_to_max_fill_locked(struct audio_buffer *buf,
124+
const uint8_t **samples,
125+
size_t bytes,
126+
int64_t *pts_ns)
127+
{
128+
size_t max_fill = max_fill_bytes_unlocked(buf);
129+
if (max_fill == 0)
130+
return bytes;
131+
132+
/* If a single decoded chunk is larger than the configured max,
133+
* keep only the newest tail so buffered mode does not start
134+
* several hundred milliseconds behind by construction. */
135+
if (bytes > max_fill) {
136+
size_t skip_bytes = bytes - max_fill;
137+
if (pts_ns && buf->sample_rate > 0 && buf->frame_size > 0) {
138+
int64_t skipped_frames =
139+
(int64_t)(skip_bytes / buf->frame_size);
140+
*pts_ns += skipped_frames * 1000000000LL /
141+
buf->sample_rate;
142+
}
143+
*samples += skip_bytes;
144+
bytes = max_fill;
145+
}
146+
147+
while (buf->fill + bytes > max_fill && buf->chunk_count > 0)
148+
skip_oldest_chunk_locked(buf);
149+
150+
if (buf->fill + bytes > max_fill) {
151+
size_t excess = buf->fill + bytes - max_fill;
152+
drop_oldest_bytes_locked(buf, excess);
153+
}
154+
155+
return bytes;
156+
}
157+
103158
/* Retire PTS chunks as data is consumed. */
104159
static void pts_consume(struct audio_buffer *buf, size_t bytes_consumed)
105160
{
@@ -228,6 +283,13 @@ size_t audio_buffer_write_pts(struct audio_buffer *buf, const uint8_t *samples,
228283
while (buf->chunk_count >= AUDIO_PTS_MAX_CHUNKS)
229284
skip_oldest_chunk_locked(buf);
230285

286+
bytes = trim_incoming_to_max_fill_locked(buf, &samples, bytes,
287+
&pts_ns);
288+
if (bytes == 0) {
289+
pthread_mutex_unlock(&buf->lock);
290+
return 0;
291+
}
292+
231293
size_t written = ring_write(buf, samples, bytes);
232294

233295
/* Record PTS chunk metadata for every successful write. */
@@ -253,6 +315,11 @@ size_t audio_buffer_write(struct audio_buffer *buf, const uint8_t *samples,
253315
return 0;
254316

255317
pthread_mutex_lock(&buf->lock);
318+
bytes = trim_incoming_to_max_fill_locked(buf, &samples, bytes, NULL);
319+
if (bytes == 0) {
320+
pthread_mutex_unlock(&buf->lock);
321+
return 0;
322+
}
256323
size_t written = ring_write(buf, samples, bytes);
257324
pthread_mutex_unlock(&buf->lock);
258325
return written;

0 commit comments

Comments
 (0)