mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
spa: node-driver: Expose the clock id as param properties
This commit is contained in:
parent
ec11859a48
commit
752de866ae
1 changed files with 301 additions and 58 deletions
|
|
@ -26,6 +26,8 @@
|
||||||
#include <spa/node/io.h>
|
#include <spa/node/io.h>
|
||||||
#include <spa/node/utils.h>
|
#include <spa/node/utils.h>
|
||||||
#include <spa/param/param.h>
|
#include <spa/param/param.h>
|
||||||
|
#include <spa/pod/filter.h>
|
||||||
|
#include <spa/pod/parser.h>
|
||||||
|
|
||||||
SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.driver");
|
SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.driver");
|
||||||
|
|
||||||
|
|
@ -48,12 +50,16 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.driver");
|
||||||
#define BW_PERIOD (3 * SPA_NSEC_PER_SEC)
|
#define BW_PERIOD (3 * SPA_NSEC_PER_SEC)
|
||||||
#define MAX_ERROR_MS 1
|
#define MAX_ERROR_MS 1
|
||||||
|
|
||||||
|
#define CLOCK_NAME_MAX 64
|
||||||
|
|
||||||
struct props {
|
struct props {
|
||||||
bool freewheel;
|
bool freewheel;
|
||||||
char clock_name[64];
|
char clock_name[CLOCK_NAME_MAX];
|
||||||
clockid_t clock_id;
|
clockid_t clock_id;
|
||||||
uint32_t freewheel_wait;
|
uint32_t freewheel_wait;
|
||||||
float resync_ms;
|
float resync_ms;
|
||||||
|
char clock_device[CLOCK_NAME_MAX];
|
||||||
|
char clock_interface[CLOCK_NAME_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct clock_offset {
|
struct clock_offset {
|
||||||
|
|
@ -73,7 +79,10 @@ struct impl {
|
||||||
|
|
||||||
uint64_t info_all;
|
uint64_t info_all;
|
||||||
struct spa_node_info info;
|
struct spa_node_info info;
|
||||||
struct spa_param_info params[1];
|
#define NODE_PropInfo 0
|
||||||
|
#define NODE_Props 1
|
||||||
|
#define N_NODE_PARAMS 2
|
||||||
|
struct spa_param_info params[N_NODE_PARAMS];
|
||||||
|
|
||||||
struct spa_hook_list hooks;
|
struct spa_hook_list hooks;
|
||||||
struct spa_callbacks callbacks;
|
struct spa_callbacks callbacks;
|
||||||
|
|
@ -99,13 +108,20 @@ struct impl {
|
||||||
struct clock_offset nsec_offset;
|
struct clock_offset nsec_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void reset_props_strings(struct props *props)
|
||||||
|
{
|
||||||
|
spa_zero(props->clock_name);
|
||||||
|
spa_zero(props->clock_device);
|
||||||
|
spa_zero(props->clock_interface);
|
||||||
|
}
|
||||||
|
|
||||||
static void reset_props(struct props *props)
|
static void reset_props(struct props *props)
|
||||||
{
|
{
|
||||||
props->freewheel = DEFAULT_FREEWHEEL;
|
props->freewheel = DEFAULT_FREEWHEEL;
|
||||||
spa_zero(props->clock_name);
|
|
||||||
props->clock_id = CLOCK_MONOTONIC;
|
props->clock_id = CLOCK_MONOTONIC;
|
||||||
props->freewheel_wait = DEFAULT_FREEWHEEL_WAIT;
|
props->freewheel_wait = DEFAULT_FREEWHEEL_WAIT;
|
||||||
props->resync_ms = DEFAULT_RESYNC_MS;
|
props->resync_ms = DEFAULT_RESYNC_MS;
|
||||||
|
reset_props_strings(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct clock_info {
|
static const struct clock_info {
|
||||||
|
|
@ -598,10 +614,280 @@ static int impl_node_process(void *object)
|
||||||
return SPA_STATUS_HAVE_DATA | SPA_STATUS_NEED_DATA;
|
return SPA_STATUS_HAVE_DATA | SPA_STATUS_NEED_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int impl_node_enum_params(void *object, int seq,
|
||||||
|
uint32_t id, uint32_t start, uint32_t num,
|
||||||
|
const struct spa_pod *filter)
|
||||||
|
{
|
||||||
|
struct impl *this = object;
|
||||||
|
struct spa_pod *param;
|
||||||
|
struct spa_pod_builder b = { 0 };
|
||||||
|
uint8_t buffer[4096];
|
||||||
|
struct spa_result_node_params result;
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
spa_return_val_if_fail(this != NULL, -EINVAL);
|
||||||
|
spa_return_val_if_fail(num != 0, -EINVAL);
|
||||||
|
|
||||||
|
result.id = id;
|
||||||
|
result.next = start;
|
||||||
|
next:
|
||||||
|
result.index = result.next++;
|
||||||
|
|
||||||
|
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case SPA_PARAM_PropInfo:
|
||||||
|
{
|
||||||
|
struct props *p = &this->props;
|
||||||
|
|
||||||
|
switch (result.index) {
|
||||||
|
case 0:
|
||||||
|
param = spa_pod_builder_add_object(&b,
|
||||||
|
SPA_TYPE_OBJECT_PropInfo, id,
|
||||||
|
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_clockId),
|
||||||
|
SPA_PROP_INFO_description, SPA_POD_String("The clock id (monotonic, realtime, etc.)"),
|
||||||
|
SPA_PROP_INFO_type, SPA_POD_String(clock_id_to_name(p->clock_id)));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
param = spa_pod_builder_add_object(&b,
|
||||||
|
SPA_TYPE_OBJECT_PropInfo, id,
|
||||||
|
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_clockDevice),
|
||||||
|
SPA_PROP_INFO_description, SPA_POD_String("The clock device (eg. /dev/ptp0)"),
|
||||||
|
SPA_PROP_INFO_type, SPA_POD_Stringn(p->clock_device, sizeof(p->clock_device)));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
param = spa_pod_builder_add_object(&b,
|
||||||
|
SPA_TYPE_OBJECT_PropInfo, id,
|
||||||
|
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_clockInterface),
|
||||||
|
SPA_PROP_INFO_description, SPA_POD_String("The clock network interface (eg. eth0)"),
|
||||||
|
SPA_PROP_INFO_type, SPA_POD_Stringn(p->clock_interface, sizeof(p->clock_interface)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SPA_PARAM_Props:
|
||||||
|
{
|
||||||
|
struct props *p = &this->props;
|
||||||
|
|
||||||
|
switch (result.index) {
|
||||||
|
case 0:
|
||||||
|
param = spa_pod_builder_add_object(&b,
|
||||||
|
SPA_TYPE_OBJECT_Props, id,
|
||||||
|
SPA_PROP_clockId, SPA_POD_String(clock_id_to_name(p->clock_id))
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
param = spa_pod_builder_add_object(&b,
|
||||||
|
SPA_TYPE_OBJECT_Props, id,
|
||||||
|
SPA_PROP_clockDevice, SPA_POD_Stringn(p->clock_device, sizeof(p->clock_device))
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
param = spa_pod_builder_add_object(&b,
|
||||||
|
SPA_TYPE_OBJECT_Props, id,
|
||||||
|
SPA_PROP_clockInterface, SPA_POD_Stringn(p->clock_interface, sizeof(p->clock_interface))
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spa_pod_filter(&b, &result.param, param, filter) < 0)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
|
||||||
|
|
||||||
|
if (++count != num)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_phc_index(struct spa_system *s, const char *name) {
|
||||||
|
#ifdef ETHTOOL_GET_TS_INFO
|
||||||
|
struct ethtool_ts_info info = {0};
|
||||||
|
struct ifreq ifr = {0};
|
||||||
|
int fd, err;
|
||||||
|
|
||||||
|
info.cmd = ETHTOOL_GET_TS_INFO;
|
||||||
|
strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
|
||||||
|
ifr.ifr_data = (char *) &info;
|
||||||
|
|
||||||
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
err = spa_system_ioctl(s, fd, SIOCETHTOOL, &ifr);
|
||||||
|
close(fd);
|
||||||
|
if (err < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
return info.phc_index;
|
||||||
|
#else
|
||||||
|
return -ENOTSUP;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_clock_id(struct impl *this, const char *s)
|
||||||
|
{
|
||||||
|
int id = clock_name_to_id(s);
|
||||||
|
if (id == -1) {
|
||||||
|
spa_log_info(this->log, "unknown clock id '%s'", s);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this->props.clock_id = id;
|
||||||
|
if (this->clock_fd >= 0) {
|
||||||
|
close(this->clock_fd);
|
||||||
|
this->clock_fd = -1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_clock_device(struct impl *this, const char *s)
|
||||||
|
{
|
||||||
|
int fd = open(s, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
spa_log_info(this->log, "failed to open clock device '%s': %m", s);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this->clock_fd >= 0) {
|
||||||
|
close(this->clock_fd);
|
||||||
|
}
|
||||||
|
this->clock_fd = fd;
|
||||||
|
this->props.clock_id = FD_TO_CLOCKID(this->clock_fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_clock_interface(struct impl *this, const char *s)
|
||||||
|
{
|
||||||
|
int phc_index = get_phc_index(this->data_system, s);
|
||||||
|
if (phc_index < 0) {
|
||||||
|
spa_log_info(this->log, "failed to get phc device index for interface '%s': %s",
|
||||||
|
s, spa_strerror(phc_index));
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
char dev[19];
|
||||||
|
spa_scnprintf(dev, sizeof(dev), "/dev/ptp%d", phc_index);
|
||||||
|
if (!parse_clock_device(this, dev)) {
|
||||||
|
spa_log_info(this->log, "failed to open clock device '%s' "
|
||||||
|
"for interface '%s': %m", dev, s);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ensure_clock_name(struct impl *this)
|
||||||
|
{
|
||||||
|
struct props *p = &this->props;
|
||||||
|
if (p->clock_name[0] == '\0') {
|
||||||
|
const char *name = clock_id_to_name(p->clock_id);
|
||||||
|
if (p->clock_device[0])
|
||||||
|
name = p->clock_device;
|
||||||
|
if (p->clock_interface[0])
|
||||||
|
name = p->clock_interface;
|
||||||
|
spa_scnprintf(p->clock_name, sizeof(p->clock_name),
|
||||||
|
"%s.%s", DEFAULT_CLOCK_PREFIX, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
||||||
|
const struct spa_pod *param)
|
||||||
|
{
|
||||||
|
struct impl *this = object;
|
||||||
|
|
||||||
|
spa_return_val_if_fail(this != NULL, -EINVAL);
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case SPA_PARAM_Props:
|
||||||
|
{
|
||||||
|
struct props *p = &this->props;
|
||||||
|
bool notify = false;
|
||||||
|
char buffer[CLOCK_NAME_MAX];
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if (param == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that the length passed to SPA_POD_OPT_Stringn() also
|
||||||
|
* includes room for the null terminator, so the content of the
|
||||||
|
* buffer variable is always guaranteed to be null terminated. */
|
||||||
|
|
||||||
|
spa_zero(buffer);
|
||||||
|
count = spa_pod_parse_object(param,
|
||||||
|
SPA_TYPE_OBJECT_Props, NULL,
|
||||||
|
SPA_PROP_clockId, SPA_POD_OPT_Stringn(buffer, sizeof(buffer))
|
||||||
|
);
|
||||||
|
if (count && parse_clock_id(this, buffer))
|
||||||
|
{
|
||||||
|
reset_props_strings(p);
|
||||||
|
notify = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
spa_zero(buffer);
|
||||||
|
count = spa_pod_parse_object(param,
|
||||||
|
SPA_TYPE_OBJECT_Props, NULL,
|
||||||
|
SPA_PROP_clockDevice, SPA_POD_OPT_Stringn(buffer, sizeof(buffer))
|
||||||
|
);
|
||||||
|
if (count && parse_clock_device(this, buffer))
|
||||||
|
{
|
||||||
|
reset_props_strings(p);
|
||||||
|
strncpy(p->clock_device, buffer, sizeof(p->clock_device));
|
||||||
|
notify = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
spa_zero(buffer);
|
||||||
|
count = spa_pod_parse_object(param,
|
||||||
|
SPA_TYPE_OBJECT_Props, NULL,
|
||||||
|
SPA_PROP_clockInterface, SPA_POD_OPT_Stringn(buffer, sizeof(buffer))
|
||||||
|
);
|
||||||
|
if (count && parse_clock_interface(this, buffer))
|
||||||
|
{
|
||||||
|
reset_props_strings(p);
|
||||||
|
strncpy(p->clock_interface, buffer, sizeof(p->clock_interface));
|
||||||
|
notify = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notify)
|
||||||
|
{
|
||||||
|
ensure_clock_name(this);
|
||||||
|
spa_log_info(this->log, "%p: setting clock to '%s'", this, p->clock_name);
|
||||||
|
if (this->started) {
|
||||||
|
do_stop(this);
|
||||||
|
do_start(this);
|
||||||
|
}
|
||||||
|
emit_node_info(this, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -ENOENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct spa_node_methods impl_node = {
|
static const struct spa_node_methods impl_node = {
|
||||||
SPA_VERSION_NODE_METHODS,
|
SPA_VERSION_NODE_METHODS,
|
||||||
.add_listener = impl_node_add_listener,
|
.add_listener = impl_node_add_listener,
|
||||||
.set_callbacks = impl_node_set_callbacks,
|
.set_callbacks = impl_node_set_callbacks,
|
||||||
|
.enum_params = impl_node_enum_params,
|
||||||
|
.set_param = impl_node_set_param,
|
||||||
.set_io = impl_node_set_io,
|
.set_io = impl_node_set_io,
|
||||||
.send_command = impl_node_send_command,
|
.send_command = impl_node_send_command,
|
||||||
.process = impl_node_process,
|
.process = impl_node_process,
|
||||||
|
|
@ -655,31 +941,6 @@ impl_get_size(const struct spa_handle_factory *factory,
|
||||||
return sizeof(struct impl);
|
return sizeof(struct impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_phc_index(struct spa_system *s, const char *name) {
|
|
||||||
#ifdef ETHTOOL_GET_TS_INFO
|
|
||||||
struct ethtool_ts_info info = {0};
|
|
||||||
struct ifreq ifr = {0};
|
|
||||||
int fd, err;
|
|
||||||
|
|
||||||
info.cmd = ETHTOOL_GET_TS_INFO;
|
|
||||||
strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
|
|
||||||
ifr.ifr_data = (char *) &info;
|
|
||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (fd < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
err = spa_system_ioctl(s, fd, SIOCETHTOOL, &ifr);
|
|
||||||
close(fd);
|
|
||||||
if (err < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
return info.phc_index;
|
|
||||||
#else
|
|
||||||
return -ENOTSUP;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
impl_init(const struct spa_handle_factory *factory,
|
impl_init(const struct spa_handle_factory *factory,
|
||||||
struct spa_handle *handle,
|
struct spa_handle *handle,
|
||||||
|
|
@ -727,9 +988,10 @@ impl_init(const struct spa_handle_factory *factory,
|
||||||
this->info.max_input_ports = 0;
|
this->info.max_input_ports = 0;
|
||||||
this->info.max_output_ports = 0;
|
this->info.max_output_ports = 0;
|
||||||
this->info.flags = SPA_NODE_FLAG_RT;
|
this->info.flags = SPA_NODE_FLAG_RT;
|
||||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
this->params[NODE_PropInfo] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||||
|
this->params[NODE_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||||
this->info.params = this->params;
|
this->info.params = this->params;
|
||||||
this->info.n_params = 0;
|
this->info.n_params = N_NODE_PARAMS;
|
||||||
|
|
||||||
reset_props(&this->props);
|
reset_props(&this->props);
|
||||||
|
|
||||||
|
|
@ -742,37 +1004,17 @@ impl_init(const struct spa_handle_factory *factory,
|
||||||
spa_scnprintf(this->props.clock_name,
|
spa_scnprintf(this->props.clock_name,
|
||||||
sizeof(this->props.clock_name), "%s", s);
|
sizeof(this->props.clock_name), "%s", s);
|
||||||
} else if (spa_streq(k, "clock.id") && this->clock_fd < 0) {
|
} else if (spa_streq(k, "clock.id") && this->clock_fd < 0) {
|
||||||
this->props.clock_id = clock_name_to_id(s);
|
if (parse_clock_id(this, s))
|
||||||
if (this->props.clock_id == -1) {
|
reset_props_strings(&this->props);
|
||||||
spa_log_warn(this->log, "unknown clock id '%s'", s);
|
|
||||||
this->props.clock_id = DEFAULT_CLOCK_ID;
|
|
||||||
}
|
|
||||||
} else if (spa_streq(k, "clock.device")) {
|
} else if (spa_streq(k, "clock.device")) {
|
||||||
if (this->clock_fd >= 0) {
|
if (parse_clock_device(this, s)) {
|
||||||
close(this->clock_fd);
|
reset_props_strings(&this->props);
|
||||||
}
|
strncpy(this->props.clock_device, s, sizeof(this->props.clock_device)-1);
|
||||||
this->clock_fd = open(s, O_RDONLY);
|
|
||||||
|
|
||||||
if (this->clock_fd == -1) {
|
|
||||||
spa_log_warn(this->log, "failed to open clock device '%s': %m", s);
|
|
||||||
} else {
|
|
||||||
this->props.clock_id = FD_TO_CLOCKID(this->clock_fd);
|
|
||||||
}
|
}
|
||||||
} else if (spa_streq(k, "clock.interface") && this->clock_fd < 0) {
|
} else if (spa_streq(k, "clock.interface") && this->clock_fd < 0) {
|
||||||
int phc_index = get_phc_index(this->data_system, s);
|
if (parse_clock_interface(this, s)) {
|
||||||
if (phc_index < 0) {
|
reset_props_strings(&this->props);
|
||||||
spa_log_warn(this->log, "failed to get phc device index for interface '%s': %s",
|
strncpy(this->props.clock_interface, s, sizeof(this->props.clock_interface)-1);
|
||||||
s, spa_strerror(phc_index));
|
|
||||||
} else {
|
|
||||||
char dev[19];
|
|
||||||
spa_scnprintf(dev, sizeof(dev), "/dev/ptp%d", phc_index);
|
|
||||||
this->clock_fd = open(dev, O_RDONLY);
|
|
||||||
if (this->clock_fd == -1) {
|
|
||||||
spa_log_warn(this->log, "failed to open clock device '%s' "
|
|
||||||
"for interface '%s': %m", dev, s);
|
|
||||||
} else {
|
|
||||||
this->props.clock_id = FD_TO_CLOCKID(this->clock_fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (spa_streq(k, "freewheel.wait")) {
|
} else if (spa_streq(k, "freewheel.wait")) {
|
||||||
this->props.freewheel_wait = atoi(s);
|
this->props.freewheel_wait = atoi(s);
|
||||||
|
|
@ -785,6 +1027,7 @@ impl_init(const struct spa_handle_factory *factory,
|
||||||
"%s.%s", DEFAULT_CLOCK_PREFIX,
|
"%s.%s", DEFAULT_CLOCK_PREFIX,
|
||||||
clock_id_to_name(this->props.clock_id));
|
clock_id_to_name(this->props.clock_id));
|
||||||
}
|
}
|
||||||
|
ensure_clock_name(this);
|
||||||
|
|
||||||
this->tracking = !clock_for_timerfd(this->props.clock_id);
|
this->tracking = !clock_for_timerfd(this->props.clock_id);
|
||||||
this->timer_clockid = this->tracking ? CLOCK_MONOTONIC : this->props.clock_id;
|
this->timer_clockid = this->tracking ? CLOCK_MONOTONIC : this->props.clock_id;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue