summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor V. Kovalenko <igor.v.kovalenko@gmail.com>2023-10-24 21:00:47 +0300
committerPulseAudio Marge Bot <pulseaudio-maintainers@lists.freedesktop.org>2023-10-25 13:21:34 +0000
commit06ccfbb996e5b8b31f04f97795e8c9f083bea332 (patch)
treecc495ce77b4407c0546a03d5c43771d90d986e2a
parent13ea94a1b630099c47506eca6d7d0d71ca3a88b8 (diff)
memblockq: Adjust tail chunk offset into memblock after split
If pa_memblockq_push needs to write into the middle of a chunk, target chunk is split into head and tail sharing the same memblock. Size of head and tail chunks is adjusted correctly, head chunk pointer into memblock remains unchanged from target chunk. The problem is with tail chunk offset into memblock which should be advanced past write region of memblock, but currently it is left as 0. This is causing an issue where seeking a few frames back into the middle of memblock and writing a frame there ends up with tail chunk referencing frames from very beginning of memblock causing corrupted output from memblockq. Fix this by adjusting tail chunk offset into memblock past write region and add a test case. Fixes #3789 Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/798>
-rw-r--r--src/pulsecore/memblockq.c1
-rw-r--r--src/tests/memblockq-test.c50
2 files changed, 51 insertions, 0 deletions
diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index 69e2147c8..3aa353609 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -353,6 +353,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
/* Drop it from the new entry */
p->index = q->index + (int64_t) d;
+ p->chunk.index = d;
p->chunk.length -= d;
/* Add it to the list */
diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c
index 2a9b88a69..c2fdae4ea 100644
--- a/src/tests/memblockq-test.c
+++ b/src/tests/memblockq-test.c
@@ -632,6 +632,55 @@ START_TEST (memblockq_test_tlength_change) {
}
END_TEST
+START_TEST (memblockq_test_push_to_middle) {
+ const char *expected_contents = "123456FE90______";
+ pa_sample_spec ss = {
+ .format = PA_SAMPLE_S16BE,
+ .rate = 48000,
+ .channels = 1
+ };
+
+ pa_memchunk silence;
+ pa_mempool *p;
+ pa_memblockq *bq;
+ pa_memchunk chunk1, chunk2;
+ pa_memchunk out;
+
+ pa_strbuf *buf;
+ char *str;
+
+ p = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true);
+ ck_assert_ptr_ne(p, NULL);
+ silence = memchunk_from_str(p, "__");
+
+ bq = pa_memblockq_new("test memblockq", 0, 200, 10, &ss, 4, 4, 40, &silence);
+
+ chunk1 = memchunk_from_str(p, "1234567890");
+ pa_memblockq_push(bq, &chunk1);
+ chunk2 = memchunk_from_str(p, "FE");
+ pa_memblockq_seek(bq, -4, 0, true);
+ pa_memblockq_push(bq, &chunk2);
+
+ pa_memblockq_peek_fixed_size(bq, 16, &out);
+
+ buf = pa_strbuf_new();
+ fprintf(stderr, "EXPECTED >%s<\n", expected_contents);
+ fprintf(stderr, "ACTUAL >");
+ dump_chunk(&out, buf);
+ fprintf(stderr, "<\n");
+ pa_memblock_unref(out.memblock);
+ str = pa_strbuf_to_string_free(buf);
+ fail_unless(pa_streq(str, expected_contents));
+ pa_xfree(str);
+
+ /* cleanup */
+ pa_memblockq_free(bq);
+ pa_memblock_unref(chunk1.memblock);
+ pa_memblock_unref(chunk2.memblock);
+ pa_memblock_unref(silence.memblock);
+ pa_mempool_unref(p);
+}
+END_TEST
int main(int argc, char *argv[]) {
int failed = 0;
@@ -650,6 +699,7 @@ int main(int argc, char *argv[]) {
tcase_add_test(tc, memblockq_test_length_changes);
tcase_add_test(tc, memblockq_test_pop_missing);
tcase_add_test(tc, memblockq_test_tlength_change);
+ tcase_add_test(tc, memblockq_test_push_to_middle);
suite_add_tcase(s, tc);
sr = srunner_create(s);