Move accounting for pending ISO packet to the reference time. Make sure
rate matching is reset on start, and reset matching on resync properly.
Allow resync on first cycle, ok since iso_io->now is valid immediately.
Silence padding larger than ISO packet may be needed for resync when
quantum is large. We can't insert silence by adding data to encoding
buffer, as the encoding buffer may be then too small and it may also be
partially filled.
Fix by inserting silence from flush_data() just before buffers would be
consumed.
Fixes ISO stream alignment at playback start.
Log something less confusing when connection to remote device drops
unexpectedly.
Silence logging transport Release() error in cases where the transport
was simultaneously deleted.
Update rate matching only once per process(). This ensures all nodes in
the group update their rate matching in the same way.
Also account for audio data in ISO output buffer in the reference time.
The calculations is in system clock domain, so when converting from
samples/duration to time rate difference should be accounted.
This does not have much effect in practice.
The rate matching calculations are done in the system clock domain. If
the driver ticks at a different rate, the correction factor needs to be
adjusted by the rate_diff.
This fixes ISO streams getting out of sync with each other when target
delay changes. This happens because typically one of them is the driver
and the other follower. Driver adjust clock rate, and follower does its
own adjustment *on top of that* so it rate matches more or less at
double speed. (The DLL of the follower to some degree corrects for
this, but can't do that when hitting RATE_CTL_DIFF_MAX and moreover it
acts with a delay.)
Change media-sink to use sco-io for HFP codecs.
Move SCO fragmentation to sco-io side.
Replace sco-sink with media-sink.
sco-sink is mostly copypaste from media-sink, and only differed in the
fragmentation detail, which can as well be handled on sco-io side.
When we simply need to change some state for the code executed in the
loop, we can use locked() instead of invoke(). This is more efficient
and avoids some context switches in the normal case.
Use TX timestamping to figure out the accurate amount of unsent data,
including controller buffers. SIOCOUTQ does not report accurate data
size as it includes overheads.
One of the ideas behind retrying the sending of a failed packet with the
poll callback was to make sure that we do not end up with missing seqnums
by missing received credit due to some jitter.
However, the rate matching behaviour for ASHA is not clear and we do not
seem to face problems in local testing by just dropping the packet.
The two sides of a ASHA pair rarely if ever start together and the
sequence number was always a bit off due to the stateful nature of
reset_buffer and ASHA needing the sequence number to be matched to
the other side.
Simplify this by setting the sequence number for ASHA just before
flushing.
Let's just directly use the next timer value from the other side
directly, and the reference time as well to calculate the expected next
sample position we want to send from on this side.
For ASHA stereo, the timer for flushing packets on both sides of a
pair should be as closed to each other as possible.
Also set seqnum before first flush so other side sends the correct
packets at the start.
The resampler delay was off by one sample, so remove the corresponding
fudge factor here. This matters for BAP output synchronization.
The resampler has also some fractional delay, so there can still be
sub-sample offset between the original and resampled timelines. This is
not currently taken into account.
Encoders and some decoders have additional internal latency that needs
to be accounted for.
This mostly matters for AAC (~40ms), as the other BT codecs have much
lower delays (~5ms).
spa_loop_invoke from data loop to main loop is not OK, as Wireplumber
currently runs its main loop with "pw_loop_enter(); pw_loop_iterate();
pw_loop_leave();" which causes the loop to be entered only when it is
processing an event.
In this case, part of the time the loop impl->thread==0, and calling
spa_loop_invoke() at such time causes the callback to be run from the
current thread, ie. in this case data loop which must not happen here.
Fix this by using eventfd instead, which is safe as the callback always
runs from the main loop.
Eventfd is also slightly more natural here, as multiple events will
group to the same mainloop cycle.
Use TX timestamps to get accurate reading of queue length and latency on
kernel + controller side.
This is new kernel BT feature, so requires kernel with the necessary
patches, available currently only in bluetooth-next/master branch.
Enabling Poll Errqueue kernel experimental Bluetooth feature is also
required for this.
Use the latency information to mitigate controller issues where ISO
streams are desynchronized due to tx problems or spontaneously when some
packets that should have been sent are left sitting in the queue, and
transmission is off by a multiple of the ISO interval. This state is
visible in the latency information, so if we see streams in a group have
persistently different latencies, drop packets to resynchronize them.
Also make corrections if the kernel/controller queues get too long, so
that we don't have too big latency there.
Since BlueZ watches the same socket for errors, and TX timestamps arrive
via the socket error queue, we need to set BT_POLL_ERRQUEUE in addition
to SO_TIMESTAMPING so that BlueZ doesn't think TX timestamps are errors.
Link: https://github.com/bluez/bluez/issues/515
Link: https://lore.kernel.org/linux-bluetooth/cover.1710440392.git.pav@iki.fi/
Link: https://lore.kernel.org/linux-bluetooth/f57e065bb571d633f811610d273711c7047af335.1712499936.git.pav@iki.fi/
Don't include the quantum in latency: the latency relative to graph
cycle start doesn't depend on the quantum. Instead, the audio packet
size determines it.
We delay the audio a bit to keep packet intervals equal, which keeps
some data in buffers.
In theory the calculation keeps one buffer free, but it doesn't
explicitly keep "extra" buffer space so in theory might flush too late
and next process() might not have free buffers. However, as we encode
next packet right away this shouldn't really occur...
Try to keep one extra spare buffer free so that the flush time is
certainly early enough.
Don't emit node error for A2DP duplex sink channel, or when BAP server.
These can occur under normal conditions (remote side suspends
transport), and are not errors.
When a sink contributing to an ISO CIG does not have data, output
silence for it, as long as at least one sink in the CIG is running.
Only if writes to sockets fail, pause all streams to reset
synchronization.
This way we write exactly the same number of packets for each CIS at the
same time, which probably is the best tested configuration in BT
adapters and devices. We also don't then have to pause output if some
sinks are not running or miss their timing, as we generate silence on
the fly.
When using iso-io, have it initialize the codec instance, and have
media-sink uses that instance, so that silence and actual audio are
encoded with the same codec.
Determine correctly if we are resampling, and have the associated delay.
Add off-by-one sample adjustment to the resampling delay, which seems to
correctly align the resampled audio with non-resampled.