mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-02-21 01:40:34 -05:00
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:
parent
9165291c43
commit
a6dcdfae0c
7 changed files with 298 additions and 23 deletions
|
|
@ -148,6 +148,8 @@ struct impl {
|
|||
uint8_t buffer_read[4096];
|
||||
struct timespec now;
|
||||
uint64_t sample_count;
|
||||
|
||||
uint32_t errqueue_count;
|
||||
};
|
||||
|
||||
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) == 0)
|
||||
|
|
@ -455,6 +457,24 @@ static int32_t decode_data(struct impl *this, uint8_t *src, uint32_t src_size,
|
|||
return dst_size - avail;
|
||||
}
|
||||
|
||||
static void handle_errqueue(struct impl *this)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* iso-io/media-sink use these for TX latency.
|
||||
* Someone else should be reading them, so drop
|
||||
* only after yielding.
|
||||
*/
|
||||
if (this->errqueue_count < 4) {
|
||||
this->errqueue_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
this->errqueue_count = 0;
|
||||
res = recv(this->fd, NULL, 0, MSG_ERRQUEUE | MSG_TRUNC);
|
||||
spa_log_trace(this->log, "%p: ignoring errqueue data (%d)", this, res);
|
||||
}
|
||||
|
||||
static void media_on_ready_read(struct spa_source *source)
|
||||
{
|
||||
struct impl *this = source->data;
|
||||
|
|
@ -467,6 +487,11 @@ static void media_on_ready_read(struct spa_source *source)
|
|||
|
||||
/* make sure the source is an input */
|
||||
if ((source->rmask & SPA_IO_IN) == 0) {
|
||||
if (source->rmask & SPA_IO_ERR) {
|
||||
handle_errqueue(this);
|
||||
return;
|
||||
}
|
||||
|
||||
spa_log_error(this->log, "source is not an input, rmask=%d", source->rmask);
|
||||
goto stop;
|
||||
}
|
||||
|
|
@ -475,6 +500,8 @@ static void media_on_ready_read(struct spa_source *source)
|
|||
goto stop;
|
||||
}
|
||||
|
||||
this->errqueue_count = 0;
|
||||
|
||||
spa_log_trace(this->log, "socket poll");
|
||||
|
||||
/* read */
|
||||
|
|
@ -688,6 +715,7 @@ static int transport_start(struct impl *this)
|
|||
}
|
||||
|
||||
this->sample_count = 0;
|
||||
this->errqueue_count = 0;
|
||||
|
||||
this->source.data = this;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue