blob: 3541abc61b4beb0572baa77962a6a1ea564d8912 [file] [log] [blame] [edit]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/media/audio/lib/clock/real_clock.h"
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/clock.h>
#include <lib/zx/time.h>
#include <zircon/syscalls/clock.h>
#include <string>
#include <gtest/gtest.h>
#include "src/media/audio/lib/clock/clone_mono.h"
#include "src/media/audio/lib/clock/utils.h"
namespace media_audio {
namespace {
constexpr auto kMonotonicDomain = Clock::kMonotonicDomain;
constexpr auto kExternalDomain = Clock::kExternalDomain;
zx::clock NewClock(zx_rights_t rights = ZX_RIGHT_DUPLICATE | ZX_RIGHT_READ | ZX_RIGHT_WRITE) {
zx::clock clock;
auto status = zx::clock::create(
ZX_CLOCK_OPT_AUTO_START | ZX_CLOCK_OPT_MONOTONIC | ZX_CLOCK_OPT_CONTINUOUS, nullptr, &clock);
FX_CHECK(status == ZX_OK) << "clock.create failed, status is " << status;
status = clock.replace(rights, &clock);
FX_CHECK(status == ZX_OK) << "clock.replace failed, status is " << status;
return clock;
}
TEST(RealClockTest, CreateUnadjustable) {
const zx_rights_t rights = ZX_RIGHT_DUPLICATE | ZX_RIGHT_READ;
auto clock = RealClock::Create("clock", NewClock(rights), kMonotonicDomain, false);
EXPECT_EQ(clock->name(), "clock");
EXPECT_EQ(clock->domain(), kMonotonicDomain);
EXPECT_FALSE(clock->adjustable());
}
TEST(RealClockTest, CreateAdjustable) {
const zx_rights_t rights = ZX_RIGHT_DUPLICATE | ZX_RIGHT_READ | ZX_RIGHT_WRITE;
auto clock = RealClock::Create("clock", NewClock(rights), kExternalDomain, true);
EXPECT_EQ(clock->name(), "clock");
EXPECT_EQ(clock->domain(), kExternalDomain);
EXPECT_TRUE(clock->adjustable());
}
TEST(RealClockTest, CreateUnadjustableMonotonic) {
auto clock = RealClock::CreateFromMonotonic("clock", kMonotonicDomain, false);
EXPECT_EQ(clock->name(), "clock");
EXPECT_EQ(clock->domain(), kMonotonicDomain);
EXPECT_FALSE(clock->adjustable());
EXPECT_TRUE(clock->IdenticalToMonotonicClock());
}
TEST(RealClockTest, CreateAdjustableMonotonic) {
auto clock = RealClock::CreateFromMonotonic("clock", kExternalDomain, true);
EXPECT_EQ(clock->name(), "clock");
EXPECT_EQ(clock->domain(), kExternalDomain);
EXPECT_TRUE(clock->adjustable());
EXPECT_TRUE(clock->IdenticalToMonotonicClock());
}
TEST(RealClockTest, Koids) {
auto c1 = NewClock();
auto c2 = ::media::audio::clock::DuplicateClock(c1);
auto c3 = NewClock();
// Koids should match for duplicated clocks.
auto clock1 = RealClock::Create("clock1", std::move(c1), kMonotonicDomain, false);
auto clock2 = RealClock::Create("clock2", std::move(c2), kMonotonicDomain, false);
auto clock3 = RealClock::Create("clock3", std::move(c3), kMonotonicDomain, false);
EXPECT_EQ(clock1->koid(), clock2->koid());
EXPECT_NE(clock1->koid(), clock3->koid());
}
TEST(RealClockTest, SetRate) {
auto clock = RealClock::Create("clock", NewClock(), kExternalDomain, true);
auto initial_snapshot = clock->to_clock_mono_snapshot();
auto r1 = zx::time(0) + zx::hour(1);
auto r2 = zx::time(0) + zx::hour(2);
// Initially should be identical to system monotonic.
EXPECT_TRUE(clock->IdenticalToMonotonicClock());
EXPECT_EQ(clock->rate_adjustment_ppm(), 0);
EXPECT_EQ(clock->ReferenceTimeFromMonotonicTime(r1), r1);
// Set the rate slower.
clock->SetRate(-1000);
EXPECT_EQ(clock->rate_adjustment_ppm(), -1000);
{
auto snapshot = clock->to_clock_mono_snapshot();
EXPECT_EQ(initial_snapshot.generation + 1, snapshot.generation);
auto to_mono = snapshot.to_clock_mono;
EXPECT_LT(to_mono.reference_delta(), to_mono.subject_delta()) << "rate should be less than 1:1";
auto m1 = clock->MonotonicTimeFromReferenceTime(r1);
auto m2 = clock->MonotonicTimeFromReferenceTime(r2);
EXPECT_LT(r2 - r1, m2 - m1);
EXPECT_FALSE(clock->IdenticalToMonotonicClock());
// This might be off by +/-1 due to rounding.
auto diff = r1 - clock->ReferenceTimeFromMonotonicTime(m1);
EXPECT_LE(std::abs(diff.get()), 1) << diff.get();
}
// Set the rate faster.
clock->SetRate(1000);
EXPECT_EQ(clock->rate_adjustment_ppm(), 1000);
{
auto snapshot = clock->to_clock_mono_snapshot();
EXPECT_EQ(initial_snapshot.generation + 2, snapshot.generation);
auto to_mono = snapshot.to_clock_mono;
EXPECT_GT(to_mono.reference_delta(), to_mono.subject_delta()) << "rate should be more than 1:1";
auto m1 = clock->MonotonicTimeFromReferenceTime(r1);
auto m2 = clock->MonotonicTimeFromReferenceTime(r2);
EXPECT_GT(r2 - r1, m2 - m1);
EXPECT_FALSE(clock->IdenticalToMonotonicClock());
// This might be off by +/-1 due to rounding.
auto diff = r1 - clock->ReferenceTimeFromMonotonicTime(m1);
EXPECT_LE(std::abs(diff.get()), 1) << diff.get();
}
}
} // namespace
} // namespace media_audio