blob: b94ec3042de55ccdb7e0eb1731d574b9a2e32258 [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.
#ifndef SRC_MEDIA_AUDIO_LIB_CLOCK_RECOVERED_CLOCK_H_
#define SRC_MEDIA_AUDIO_LIB_CLOCK_RECOVERED_CLOCK_H_
#include <lib/syslog/cpp/macros.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/clock.h>
#include <memory>
#include <optional>
#include <string>
#include "src/media/audio/lib/clock/clock.h"
#include "src/media/audio/lib/clock/pid_control.h"
namespace media_audio {
// A wrapper that allows "recovering" a clock from a stream of position updates. Each position
// update has the form `(mono_time, position)`, where `mono_time` is the system monotonic time
// at which the `position` was observed. The `position` is any 64-bit integer, such as an index
// into a byte stream, where the `position` must advance at a constant rate relative to the
// reference clock we are recovering.
//
// Given a position update, combined with a function `ref_time(p)` that translates from position
// to the expected reference time at that position, we can compute a clock error:
//
// ```
// mono_time - clock->MonotonicTimeFromReferenceTime(ref_time(position))
// ```
//
// If this clock error is non-zero, the RecoveredClock is adjusted to (attempt to) eliminate that
// error in future position readings. For example, a RecoveredClock can approximate a hardware
// device clock that can be read only indirectly via position updates from a device driver.
//
// All methods are safe to call from any thread.
class RecoveredClock : public Clock {
public:
// TODO(fxbug.dev/87651): move PidControl to media_audio.
using PidControl = media::audio::clock::PidControl;
// Creates a RecoveredClock which drives the given `backing_clock`, which must be adjustable.
// The backing clock is adjusted using a PID controller with the given coefficients.
static std::shared_ptr<RecoveredClock> Create(std::string_view name,
std::shared_ptr<Clock> backing_clock,
PidControl::Coefficients pid_coefficients);
std::string_view name() const override { return name_; }
zx_koid_t koid() const override { return backing_clock_->koid(); }
uint32_t domain() const override { return backing_clock_->domain(); }
bool adjustable() const override { return false; }
zx::time now() const override { return backing_clock_->now(); }
ToClockMonoSnapshot to_clock_mono_snapshot() const override {
return backing_clock_->to_clock_mono_snapshot();
}
// Although a RecoveredClock's rate can change over time, the clock cannot be adjusted directly.
// All adjustments happen via `Reset` and `Update`.
void SetRate(int32_t rate_adjust_ppm) override {
FX_CHECK(false) << "RecoveredClocks are not adjustable";
}
std::optional<zx::clock> DuplicateZxClockReadOnly() const override {
return backing_clock_->DuplicateZxClockReadOnly();
}
// Resets the clock's rate to match the system monotonic clock, clears all accumulated state,
// and starts using a new translation from position to reference time.
void Reset(zx::time mono_reset_time, media::TimelineFunction pos_to_ref_time);
// Tunes the clock based on an updated position. Returns the clock's predicted monotonic time.
// There must be at least one Reset before the first Update. The sequence of Reset and
// Update calls must use monotonically-increasing values for both time and position.
zx::time Update(zx::time mono_time, int64_t position);
private:
RecoveredClock(std::string_view name, std::shared_ptr<Clock> backing_clock,
PidControl::Coefficients pid_coefficients)
: name_(name), backing_clock_(std::move(backing_clock)), pid_(pid_coefficients) {}
void SetBackingRate(int32_t rate_adjust_ppm) TA_REQ(mutex_);
const std::string name_;
const std::shared_ptr<Clock> backing_clock_;
std::mutex mutex_;
int32_t current_backing_rate_ppm_ TA_GUARDED(mutex_) = 0;
std::optional<media::TimelineFunction> pos_to_ref_time_ TA_GUARDED(mutex_);
PidControl pid_ TA_GUARDED(mutex_);
};
} // namespace media_audio
#endif // SRC_MEDIA_AUDIO_LIB_CLOCK_RECOVERED_CLOCK_H_