diff --git a/spa/plugins/bluez5/a2dp-sink.c b/spa/plugins/bluez5/a2dp-sink.c index 64acafa86..be6b7efac 100644 --- a/spa/plugins/bluez5/a2dp-sink.c +++ b/spa/plugins/bluez5/a2dp-sink.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -82,12 +83,14 @@ struct port { uint64_t info_all; struct spa_port_info info; struct spa_io_buffers *io; + struct spa_latency_info latency; #define IDX_EnumFormat 0 #define IDX_Meta 1 #define IDX_IO 2 #define IDX_Format 3 #define IDX_Buffers 4 -#define N_PORT_PARAMS 5 +#define IDX_Latency 5 +#define N_PORT_PARAMS 6 struct spa_param_info params[N_PORT_PARAMS]; struct buffer buffers[MAX_BUFFERS]; @@ -336,6 +339,27 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) static void emit_node_info(struct impl *this, bool full); +static void emit_port_info(struct impl *this, struct port *port, bool full); + +static void set_latency(struct impl *this, bool emit_latency) +{ + struct port *port = &this->port; + int64_t delay; + + if (this->transport == NULL) + return; + + delay = spa_bt_transport_get_delay_nsec(this->transport); + delay += SPA_CLAMP(this->props.latency_offset, -delay, INT64_MAX / 2); + port->latency.min_ns = port->latency.max_ns = delay; + + if (emit_latency) { + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->params[IDX_Latency].flags ^= SPA_PARAM_INFO_SERIAL; + emit_port_info(this, port, false); + } +} + static int apply_props(struct impl *this, const struct spa_pod *param) { struct props new_props = this->props; @@ -353,6 +377,10 @@ static int apply_props(struct impl *this, const struct spa_pod *param) changed = (memcmp(&new_props, &this->props, sizeof(struct props)) != 0); this->props = new_props; + + if (changed) + set_latency(this, true); + return changed; } @@ -1065,6 +1093,16 @@ impl_node_port_enum_params(void *object, int seq, } break; + case SPA_PARAM_Latency: + switch (result.index) { + case 0: + param = spa_latency_build(&b, id, &port->latency); + break; + default: + return 0; + } + break; + default: return -ENOENT; } @@ -1142,6 +1180,7 @@ static int port_set_format(struct impl *this, struct port *port, port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate); port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); + port->params[IDX_Latency].flags ^= SPA_PARAM_INFO_SERIAL; } else { port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); @@ -1303,6 +1342,13 @@ static const struct spa_node_methods impl_node = { .process = impl_node_process, }; +static void transport_delay_changed(void *data) +{ + struct impl *this = data; + spa_log_debug(this->log, "transport %p delay changed", this->transport); + set_latency(this, true); +} + static int do_transport_destroy(struct spa_loop *loop, bool async, uint32_t seq, @@ -1324,7 +1370,8 @@ static void transport_destroy(void *data) static const struct spa_bt_transport_events transport_events = { SPA_VERSION_BT_TRANSPORT_EVENTS, - .destroy = transport_destroy, + .delay_changed = transport_delay_changed, + .destroy = transport_destroy, }; static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) @@ -1427,8 +1474,15 @@ impl_init(const struct spa_handle_factory *factory, port->params[IDX_IO] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + port->params[IDX_Latency] = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); port->info.params = port->params; port->info.n_params = N_PORT_PARAMS; + + port->latency = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); + port->latency.min_quantum = 1.0f; + port->latency.max_quantum = 1.0f; + set_latency(this, false); + spa_list_init(&port->ready); if (info && (str = spa_dict_lookup(info, SPA_KEY_API_BLUEZ5_TRANSPORT))) diff --git a/spa/plugins/bluez5/a2dp-source.c b/spa/plugins/bluez5/a2dp-source.c index 97bc7cf5f..2934899fd 100644 --- a/spa/plugins/bluez5/a2dp-source.c +++ b/spa/plugins/bluez5/a2dp-source.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -79,12 +80,14 @@ struct port { uint64_t info_all; struct spa_port_info info; struct spa_io_buffers *io; + struct spa_latency_info latency; #define IDX_EnumFormat 0 #define IDX_Meta 1 #define IDX_IO 2 #define IDX_Format 3 #define IDX_Buffers 4 -#define N_PORT_PARAMS 5 +#define IDX_Latency 5 +#define N_PORT_PARAMS 6 struct spa_param_info params[N_PORT_PARAMS]; struct buffer buffers[MAX_BUFFERS]; @@ -950,6 +953,16 @@ impl_node_port_enum_params(void *object, int seq, } break; + case SPA_PARAM_Latency: + switch (result.index) { + case 0: + param = spa_latency_build(&b, id, &port->latency); + break; + default: + return 0; + } + break; + default: return -ENOENT; } @@ -1030,6 +1043,7 @@ static int port_set_format(struct impl *this, struct port *port, port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate); port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); + port->params[IDX_Latency].flags ^= SPA_PARAM_INFO_SERIAL; } else { port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); @@ -1343,9 +1357,14 @@ impl_init(const struct spa_handle_factory *factory, port->params[IDX_IO] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + port->params[IDX_Latency] = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); port->info.params = port->params; port->info.n_params = N_PORT_PARAMS; + port->latency = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); + port->latency.min_quantum = 1.0f; + port->latency.max_quantum = 1.0f; + /* Init the buffer lists */ spa_list_init(&port->ready); spa_list_init(&port->free); diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index b04360ee0..9897bc094 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -1909,6 +1909,7 @@ static int transport_update_props(struct spa_bt_transport *transport, spa_log_debug(monitor->log, "transport %p: %s=%02x", transport, key, value); transport->delay = value; + spa_bt_transport_emit_delay_changed(transport); } next: dbus_message_iter_next(props_iter); diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index 908fc593c..2688c0426 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -488,6 +488,7 @@ struct spa_bt_transport_events { uint32_t version; void (*destroy) (void *data); + void (*delay_changed) (void *data); void (*state_changed) (void *data, enum spa_bt_transport_state old, enum spa_bt_transport_state state); void (*volume_changed) (void *data); @@ -568,6 +569,7 @@ int spa_bt_transport_ensure_sco_io(struct spa_bt_transport *t, struct spa_loop * struct spa_bt_transport_events, \ m, v, ##__VA_ARGS__) #define spa_bt_transport_emit_destroy(t) spa_bt_transport_emit(t, destroy, 0) +#define spa_bt_transport_emit_delay_changed(t) spa_bt_transport_emit(t, delay_changed, 0) #define spa_bt_transport_emit_state_changed(t,...) spa_bt_transport_emit(t, state_changed, 0, __VA_ARGS__) #define spa_bt_transport_emit_volume_changed(t) spa_bt_transport_emit(t, volume_changed, 0) diff --git a/spa/plugins/bluez5/sco-sink.c b/spa/plugins/bluez5/sco-sink.c index e1b176676..3594523d9 100644 --- a/spa/plugins/bluez5/sco-sink.c +++ b/spa/plugins/bluez5/sco-sink.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -75,12 +76,14 @@ struct port { struct spa_port_info info; struct spa_io_buffers *io; struct spa_io_rate_match *rate_match; + struct spa_latency_info latency; #define IDX_EnumFormat 0 #define IDX_Meta 1 #define IDX_IO 2 #define IDX_Format 3 #define IDX_Buffers 4 -#define N_PORT_PARAMS 5 +#define IDX_Latency 5 +#define N_PORT_PARAMS 6 struct spa_param_info params[N_PORT_PARAMS]; struct buffer buffers[MAX_BUFFERS]; @@ -896,6 +899,16 @@ impl_node_port_enum_params(void *object, int seq, } break; + case SPA_PARAM_Latency: + switch (result.index) { + case 0: + param = spa_latency_build(&b, id, &port->latency); + break; + default: + return 0; + } + break; + default: return -ENOENT; } @@ -957,6 +970,7 @@ static int port_set_format(struct impl *this, struct port *port, port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate); port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); + port->params[IDX_Latency].flags ^= SPA_PARAM_INFO_SERIAL; } else { port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); @@ -1237,8 +1251,14 @@ impl_init(const struct spa_handle_factory *factory, port->params[IDX_IO] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + port->params[IDX_Latency] = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); port->info.params = port->params; port->info.n_params = N_PORT_PARAMS; + + port->latency = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); + port->latency.min_quantum = 1.0f; + port->latency.max_quantum = 1.0f; + spa_list_init(&port->ready); if (info && (str = spa_dict_lookup(info, SPA_KEY_API_BLUEZ5_TRANSPORT))) diff --git a/spa/plugins/bluez5/sco-source.c b/spa/plugins/bluez5/sco-source.c index 8783eb552..03d87f97c 100644 --- a/spa/plugins/bluez5/sco-source.c +++ b/spa/plugins/bluez5/sco-source.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -77,12 +78,14 @@ struct port { struct spa_port_info info; struct spa_io_buffers *io; struct spa_io_rate_match *rate_match; + struct spa_latency_info latency; #define IDX_EnumFormat 0 #define IDX_Meta 1 #define IDX_IO 2 #define IDX_Format 3 #define IDX_Buffers 4 -#define N_PORT_PARAMS 5 +#define IDX_Latency 5 +#define N_PORT_PARAMS 6 struct spa_param_info params[N_PORT_PARAMS]; struct buffer buffers[MAX_BUFFERS]; @@ -929,6 +932,16 @@ impl_node_port_enum_params(void *object, int seq, } break; + case SPA_PARAM_Latency: + switch (result.index) { + case 0: + param = spa_latency_build(&b, id, &port->latency); + break; + default: + return 0; + } + break; + default: return -ENOENT; } @@ -992,6 +1005,7 @@ static int port_set_format(struct impl *this, struct port *port, port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate); port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); + port->params[IDX_Latency].flags ^= SPA_PARAM_INFO_SERIAL; } else { port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); @@ -1299,9 +1313,14 @@ impl_init(const struct spa_handle_factory *factory, port->params[IDX_IO] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); port->params[IDX_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[IDX_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + port->params[IDX_Latency] = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); port->info.params = port->params; port->info.n_params = N_PORT_PARAMS; + port->latency = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); + port->latency.min_quantum = 1.0f; + port->latency.max_quantum = 1.0f; + /* Init the buffer lists */ spa_list_init(&port->ready); spa_list_init(&port->free);