When interpolating with rate correction != 1.0, don't floor the
resulting input rate to the nearest smallest integer.
This allows rate corrections < 1/in_rate to have some effect, and
reduces jumps in the response. One of the jumps is inconveniently
between rate=1.0 and rate=1.0+eps and will cause rate corrections to
oscillate if target rate varies close to 1.0.
If phase is float, calculations in impl_native_in_len/out_len can
produce wrong results due to rounding error.
It's probably better to not be in the business of predicting
floating-point rounding, so replace this by fixed-point arithmetic.
Also make sure `offset+1` cannot overflow data->filter array in
do_resample_inter* due to float multiplication possibly rounding up.
If phase is float, calculations in impl_native_in_len/out_len don't
necessarily match with do_resample, because e.g.
float phase0 = 7999.99;
float phase = phase0;
int frac = 8000, out_rate = 8000, n = 64, count = 0;
for (int j = 0; j < n; ++j) {
phase += frac;
if (phase >= out_rate) {
phase -= out_rate;
count++;
}
}
printf("count = %d\n", count); /* count = 64 */
count = (int)(phase0 + n*frac) / out_rate;
printf("count = %d\n", count); /* count = 65 */
don't give the same result.
Also add test where floating point multiplication rounding up to nearest
in
float ph = phase * pm;
uint32_t offset = (uint32_t)floorf(ph);
computation results to offset+1 > data->n_phases, accessing filter array
beyond bounds. (The accessed value is still inside allocated memory
block, but contains unrelated values; the test passes silently.)
Using the parser for the spa_pod_sequence in the data buffers is
required in order to safely read the pods while there could be
concurrent writes.
See #4822
Make a new body.h file with some functions to deal with pod and their
body. Make the iter.h functions use mostly this.
Rework the parser so that it only uses body.h functions. With the separation
of pod+body, we can read and verify the pod once and then use the
verified copy to handle the rest of the body safely.
We do this because iter.h only works in pods in memory that doesn't change
because it is vulnerable to modifications of the data after verifying it.
The new parser is not vulnerable to this and will not cause invalid
memory access when used on shared memory. There is however no need for
atomic operations to read the headers, whever is read is either valid
and useable of invalid and rejected.
See #4822
Use get_string() to get a pointer to the string in the pod so that we
also check if it has a 0 terminator.
Fix the test case now that is_string returns true even for non
zero-terminated strings.
The _is_type() macros should simply check the type in the header and if
the size is large enough to look into the type specifics. Further
validation of the values should be done when the value is retrieved.
Following this logic, the String zero byte check should be done in the
get_string() function.
The parser does not check that POD arrays have the correct size for
their type, so the calling code must do that.
This also enumerates some of the code that cannot handle the size of the
values of an array not being the exact expected size for its type.
There is a lot of it.
We already know that we could succesfully allocate enough space for the
bytes because we checked that before so simply move to the body of the
new bytes pod. We don't need to do the extensive checks we do in deref.
Add a function that can build a pod from a pod definition, a body data
and a suffix.
We can use this to build strings and bytes and arrays like the other
primitives, which makes it possible to add them to choices or arrays.
Fixes#4588
SPA does not respect the C strict aliasing rules at all, so any code
that uses it must be built with -fno-strict-aliasing. Furthermore,
there is code in SPA that compares pointers that point to different
objects, so -fno-strict-overflow is also needed.
Direct timestamp mode was incorrectly using over/underrun detection logic
and fill level tracking logic that is actually meant for the other mode
(referred to from now on as "constant latency mode"). Over/underruns are
tracked implicitly in the direct timestamp mode, and the absolute fill
level is not relevant in that mode, since the latency is not needed to
be constant then.
Also improve log lines and the RTP module documentation to define these
buffer modes clearly and explain their differences and use cases.
Opus and MIDI code get TODOs added, since their direct timestamp mode
implementations still may be incorrect. Fixing those will be done in
a separate commit.
When a stream has some delay, a time t1 + delay has to be read in time
t1 to play it when expected.
Decrease target_buffer by delay to start playback sooner, so sound
is played at correct time when delay is applied.
Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
We don't actually need to calculate the GCD for each resampler rate
update. The GCD is only used to scale the in/out rates when using the
full resampler and this we can cache and reuse when we did the setup.
The interpolating resampler can work perfectly fine with a GCD of 1 and
so we can just assume that.
spa_alsa_read is called from the source process function when we are a
follower and no buffer is ready yet.
Part of the rate correction was performed by the ALSA driver when it
woke up but now, the resampler has updated the requested size and we
need to requery it before we can start reading samples.
Otherwise, we end up with requested samples from before the rate update
and we might not give enough samples to the resampler. In that case, the
adapter will call us again and we will again try to produce a buffer
worth of the requested samples, which will xrun.
Use the area to compare two rectangles. Use the width to break a tie.
This way the sorting is at least a bit more predictable and independent
of the order of the arguments.
We also need to close the SynObj fd we got, just like we close any
DmaBuf or MemFd.
Make sure we get a compiler error when we add more items to the
data type enumeration later.
Fixes#4807
Disable the padding to pod alignment for everything when we are building
the body of an array or choice.
This makes it possible to use bytes or strings or any other pod of a
fixed size as entries in arrays or choice.
Assume that all the functions that take a type/size/data from a pod have
at least the right number of bytes in the data for the given type.
Callers need to ensure this.
Fix the callers of such functions to always make sure they deref a pod
type/size/body into something of at least the min size of the type.
Do a more thorough test of the choice type by not only checking the type
but also if the size is at least large enough to be able to cast it to
the pod_choice type and look at the contents.
In the filter, don't _deref or use _frame before we are going to add
more pods to the builder. If we are using a dynamic builder, the
dereffed pod might become invalid when the memory is reallocated.
Instead, take the offset of the frame and deref later when we are not
going to add more things.
Previously, valgrind was warning that
Syscall param sendmsg(msg.msg_iov[0]) points to uninitialised byte(s)
this was caused by uninitialized values being serialized for IPC.
Specifically, not all members of the `pw_endpoint_info` struct were
initialized, which caused uninitialized bytes to end up in the IPC
buffers due to the `pw_endpoint_emit_info()` in `endpoint_add_listener()`.
Fix that by initializing the missed `id` and `flags` members.