mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04:00
bluez5: media-sink: resync ISO streams on playback start
Resynchronize ISO streams on playback (re)start, so the stream positions are aligned immediately. This is better than relying on rate matching to correct any offsets.
This commit is contained in:
parent
261fb64849
commit
5d1782760c
3 changed files with 49 additions and 33 deletions
|
|
@ -157,9 +157,8 @@ static void group_on_timeout(struct spa_source *source)
|
|||
|
||||
if (!stream->sink)
|
||||
continue;
|
||||
if (stream->idle)
|
||||
continue;
|
||||
if (group->paused) {
|
||||
if (stream->idle || group->paused) {
|
||||
stream->this.resync = true;
|
||||
stream->this.size = 0;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -355,13 +354,10 @@ void spa_bt_iso_io_set_cb(struct spa_bt_iso_io *this, spa_bt_iso_io_pull_t pull,
|
|||
set_timers(stream->group);
|
||||
|
||||
stream->idle = true;
|
||||
stream->this.resync = true;
|
||||
|
||||
if (pull == NULL) {
|
||||
stream->this.size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pull data now for the next interval */
|
||||
stream->this.now = stream->group->next;
|
||||
stream->pull(&stream->this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@
|
|||
*/
|
||||
struct spa_bt_iso_io
|
||||
{
|
||||
uint64_t now;
|
||||
uint64_t duration;
|
||||
uint64_t now; /**< Reference time position of next packet (read-only) */
|
||||
uint64_t duration; /**< ISO interval duration in ns (read-only) */
|
||||
bool resync; /**< Resync position for next packet; (pull callback sets to
|
||||
* false when done) */
|
||||
|
||||
uint32_t timestamp;
|
||||
uint8_t buf[4096];
|
||||
size_t size;
|
||||
uint32_t timestamp; /**< Packet timestamp (set by pull callback) */
|
||||
uint8_t buf[4096]; /**< Packet data (set by pull callback) */
|
||||
size_t size; /**< Packet size (set by pull callback) */
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ struct props {
|
|||
#define BUFFER_SIZE (8192*8)
|
||||
#define RATE_CTL_DIFF_MAX 0.005
|
||||
|
||||
/* Wait for two cycles before trying to sync ISO. On start/driver reassign,
|
||||
* first cycle may have strange number of samples. */
|
||||
#define RESYNC_CYCLES 2
|
||||
|
||||
struct buffer {
|
||||
uint32_t id;
|
||||
#define BUFFER_FLAG_OUT (1<<0)
|
||||
|
|
@ -129,6 +133,7 @@ struct impl {
|
|||
unsigned int following:1;
|
||||
unsigned int is_output:1;
|
||||
unsigned int flush_pending:1;
|
||||
unsigned int iso_pending:1;
|
||||
|
||||
unsigned int is_duplex:1;
|
||||
unsigned int is_internal:1;
|
||||
|
|
@ -160,8 +165,7 @@ struct impl {
|
|||
|
||||
int need_flush;
|
||||
bool fragment;
|
||||
bool resync;
|
||||
bool have_iso_packet;
|
||||
uint32_t resync;
|
||||
uint32_t block_size;
|
||||
uint8_t buffer[BUFFER_SIZE];
|
||||
uint32_t buffer_used;
|
||||
|
|
@ -308,7 +312,7 @@ static int do_reassign_io(struct spa_loop *loop,
|
|||
bool following;
|
||||
|
||||
if (this->position != info->position || this->clock != info->clock)
|
||||
this->resync = true;
|
||||
this->resync = RESYNC_CYCLES;
|
||||
|
||||
this->position = info->position;
|
||||
this->clock = info->clock;
|
||||
|
|
@ -716,6 +720,9 @@ static int flush_data(struct impl *this, uint64_t now_time)
|
|||
if (!this->flush_timer_source.loop && !this->transport->iso_io)
|
||||
return -EIO;
|
||||
|
||||
if (this->transport->iso_io && !this->iso_pending)
|
||||
return 0;
|
||||
|
||||
total_frames = 0;
|
||||
again:
|
||||
written = 0;
|
||||
|
|
@ -788,7 +795,7 @@ again:
|
|||
if (this->transport->iso_io) {
|
||||
struct spa_bt_iso_io *iso_io = this->transport->iso_io;
|
||||
|
||||
if (this->need_flush && !this->have_iso_packet) {
|
||||
if (this->need_flush) {
|
||||
size_t avail = SPA_MIN(this->buffer_used, sizeof(iso_io->buf));
|
||||
|
||||
spa_log_trace(this->log, "%p: ISO put fd:%d size:%u sn:%u ts:%u now:%"PRIu64,
|
||||
|
|
@ -799,7 +806,7 @@ again:
|
|||
memcpy(iso_io->buf, this->buffer, avail);
|
||||
iso_io->size = avail;
|
||||
iso_io->timestamp = this->timestamp;
|
||||
this->have_iso_packet = true;
|
||||
this->iso_pending = false;
|
||||
|
||||
reset_buffer(this);
|
||||
}
|
||||
|
|
@ -954,9 +961,7 @@ static void media_iso_pull(struct spa_bt_iso_io *iso_io)
|
|||
struct port *port = &this->port;
|
||||
const double period = 0.1 * SPA_NSEC_PER_SEC;
|
||||
uint64_t duration_ns;
|
||||
double value, target, err;
|
||||
|
||||
this->have_iso_packet = false;
|
||||
double value, target, err, max_err;
|
||||
|
||||
if (this->resync || !this->position) {
|
||||
spa_bt_rate_control_init(&port->ratectl, 0);
|
||||
|
|
@ -979,19 +984,28 @@ static void media_iso_pull(struct spa_bt_iso_io *iso_io)
|
|||
value = (int64_t)iso_io->now - (int64_t)get_reference_time(this, &duration_ns);
|
||||
target = iso_io->duration * 3/2;
|
||||
err = value - target;
|
||||
max_err = iso_io->duration;
|
||||
|
||||
if (err > iso_io->duration) {
|
||||
uint32_t req = err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
|
||||
if (err > max_err || (iso_io->resync && err > 0)) {
|
||||
unsigned int req = err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
|
||||
|
||||
spa_log_debug(this->log, "%p: ISO sync reset frames:%u", this, (unsigned int)req);
|
||||
if (req > 0) {
|
||||
spa_bt_rate_control_init(&port->ratectl, 0);
|
||||
drop_frames(this, req);
|
||||
spa_log_debug(this->log, "%p: ISO sync skip frames:%u resync:%d",
|
||||
this, req, iso_io->resync);
|
||||
}
|
||||
} else if (-err > max_err || (iso_io->resync && -err > 0)) {
|
||||
unsigned int req = -err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
|
||||
static const uint8_t empty[8192] = {0};
|
||||
|
||||
spa_bt_rate_control_init(&port->ratectl, 0);
|
||||
drop_frames(this, req);
|
||||
} else if (-err > iso_io->duration) {
|
||||
uint32_t req = -err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
|
||||
|
||||
spa_log_debug(this->log, "%p: ISO sync skip flush frames:%u", this, (unsigned int)req);
|
||||
return;
|
||||
if (req > 0) {
|
||||
spa_bt_rate_control_init(&port->ratectl, 0);
|
||||
req = SPA_MIN(req, sizeof(empty) / port->frame_size);
|
||||
add_data(this, empty, req * port->frame_size);
|
||||
spa_log_debug(this->log, "%p: ISO sync pad frames:%u resync:%d",
|
||||
this, req, iso_io->resync);
|
||||
}
|
||||
} else {
|
||||
spa_bt_rate_control_update(&port->ratectl, err, 0,
|
||||
iso_io->duration, period, RATE_CTL_DIFF_MAX);
|
||||
|
|
@ -1003,7 +1017,10 @@ static void media_iso_pull(struct spa_bt_iso_io *iso_io)
|
|||
port->ratectl.corr);
|
||||
}
|
||||
|
||||
iso_io->resync = false;
|
||||
|
||||
done:
|
||||
this->iso_pending = true;
|
||||
flush_data(this, this->current_time);
|
||||
}
|
||||
|
||||
|
|
@ -1216,9 +1233,9 @@ static int transport_start(struct impl *this)
|
|||
this->flush_source.rmask = 0;
|
||||
spa_loop_add_source(this->data_loop, &this->flush_source);
|
||||
|
||||
this->resync = true;
|
||||
|
||||
this->resync = RESYNC_CYCLES;
|
||||
this->flush_pending = false;
|
||||
this->iso_pending = false;
|
||||
|
||||
this->transport_started = true;
|
||||
|
||||
|
|
@ -1836,7 +1853,8 @@ static int impl_node_process(void *object)
|
|||
}
|
||||
|
||||
this->process_time = this->current_time;
|
||||
this->resync = false;
|
||||
if (this->resync)
|
||||
--this->resync;
|
||||
|
||||
setup_matching(this);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue