+static inline
+uint64_t cycles_from_ns(uint64_t frequency, uint64_t ns)
+{
+ uint64_t cycles;
+
+ /* 1GHz */
+ if (frequency == UINT64_C(1000000000)) {
+ cycles = ns;
+ } else {
+ cycles = (uint64_t) (((double) ns * (double) frequency) / 1e9);
+ }
+
+ return cycles;
+}
+
+static
+void calibrate_clock_class_offsets(int64_t *offset_seconds,
+ uint64_t *offset_cycles, uint64_t freq)
+{
+ if (*offset_cycles >= freq) {
+ const uint64_t s_in_offset_cycles = *offset_cycles / freq;
+
+ *offset_seconds += (int64_t) s_in_offset_cycles;
+ *offset_cycles -= (s_in_offset_cycles * freq);
+ }
+}
+
+static
+void apply_clock_class_offset(struct ctx *ctx,
+ struct bt_private_clock_class *clock)
+{
+ uint64_t freq;
+ int64_t offset_s_to_apply = ctx->decoder_config.clock_class_offset_s;
+ uint64_t offset_ns_to_apply;
+ int64_t cur_offset_s;
+ uint64_t cur_offset_cycles;
+
+ if (ctx->decoder_config.clock_class_offset_s == 0 &&
+ ctx->decoder_config.clock_class_offset_ns == 0) {
+ goto end;
+ }
+
+ /* Transfer nanoseconds to seconds as much as possible */
+ if (ctx->decoder_config.clock_class_offset_ns < 0) {
+ const int64_t abs_ns = -ctx->decoder_config.clock_class_offset_ns;
+ const int64_t abs_extra_s = abs_ns / INT64_C(1000000000) + 1;
+ const int64_t extra_s = -abs_extra_s;
+ const int64_t offset_ns = ctx->decoder_config.clock_class_offset_ns -
+ (extra_s * INT64_C(1000000000));
+
+ BT_ASSERT(offset_ns > 0);
+ offset_ns_to_apply = (uint64_t) offset_ns;
+ offset_s_to_apply += extra_s;
+ } else {
+ const int64_t extra_s = ctx->decoder_config.clock_class_offset_ns /
+ INT64_C(1000000000);
+ const int64_t offset_ns = ctx->decoder_config.clock_class_offset_ns -
+ (extra_s * INT64_C(1000000000));
+
+ BT_ASSERT(offset_ns >= 0);
+ offset_ns_to_apply = (uint64_t) offset_ns;
+ offset_s_to_apply += extra_s;
+ }
+
+ freq = bt_clock_class_get_frequency(
+ bt_private_clock_class_as_clock_class(clock));
+ bt_clock_class_get_offset(bt_private_clock_class_as_clock_class(clock),
+ &cur_offset_s, &cur_offset_cycles);
+
+ /* Apply offsets */
+ cur_offset_s += offset_s_to_apply;
+ cur_offset_cycles += cycles_from_ns(freq, offset_ns_to_apply);
+
+ /*
+ * Recalibrate offsets because the part in cycles can be greater
+ * than the frequency at this point.
+ */
+ calibrate_clock_class_offsets(&cur_offset_s, &cur_offset_cycles, freq);
+
+ /* Set final offsets */
+ bt_private_clock_class_set_offset(clock, cur_offset_s, cur_offset_cycles);
+
+end:
+ return;
+}
+