bluez5: iso-io: track and apply corrections to tx latency

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/
This commit is contained in:
Pauli Virtanen 2024-02-20 23:01:07 +02:00
parent 9165291c43
commit a6dcdfae0c
7 changed files with 298 additions and 23 deletions

View file

@ -45,6 +45,8 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.bluez5.sink.media");
#undef SPA_LOG_TOPIC_DEFAULT
#define SPA_LOG_TOPIC_DEFAULT &log_topic
#include "bt-latency.h"
#define DEFAULT_CLOCK_NAME "clock.system.monotonic"
struct props {
@ -57,6 +59,7 @@ struct props {
#define MAX_BUFFERS 32
#define BUFFER_SIZE (8192*8)
#define RATE_CTL_DIFF_MAX 0.005
#define LATENCY_PERIOD (200 * SPA_NSEC_PER_MSEC)
/* Wait for two cycles before trying to sync ISO. On start/driver reassign,
* first cycle may have strange number of samples. */
@ -1086,9 +1089,18 @@ static void media_on_flush_error(struct spa_source *source)
{
struct impl *this = source->data;
if (source->rmask & SPA_IO_ERR) {
/* TX timestamp info? */
if (this->transport && this->transport->iso_io)
if (spa_bt_iso_io_recv_errqueue(this->transport->iso_io) == 0)
return;
/* Otherwise: actual error */
}
spa_log_trace(this->log, "%p: flush event", this);
if (source->rmask & (SPA_IO_ERR | SPA_IO_HUP)) {
if (source->rmask & (SPA_IO_HUP | SPA_IO_ERR)) {
spa_log_warn(this->log, "%p: error %d", this, source->rmask);
if (this->flush_source.loop)
spa_loop_remove_source(this->data_loop, &this->flush_source);
@ -1372,7 +1384,6 @@ static int do_remove_transport_source(struct spa_loop *loop,
if (this->flush_source.loop)
spa_loop_remove_source(this->data_loop, &this->flush_source);
if (this->flush_timer_source.loop)
spa_loop_remove_source(this->data_loop, &this->flush_timer_source);
enable_flush_timer(this, false);