# audio-clock-bsd
[](./LICENSE)
[](https://www.rust-lang.org)
Clock synchronization and timestamp conversion for real-time audio. It provides
the `ClockSource` trait — the single contract a host application uses to map
between an audio **sample index** and a wall-clock **PTP timestamp**
(nanoseconds) — together with an anchor-based conversion and two backends.
> The doc comments on each public item are the primary reference. This README is
> an overview only.
## Overview
`audio-clock-bsd` lets an audio engine timestamp its samples for distributed
playback (e.g. PTP-aligned streaming) or for offline alignment. The
sample-index ↔ timestamp map is a pure linear function anchored at a known
reference point; [`ClockAnchor`] performs the checked arithmetic, and the two
conversions are allocation-free and safe to call from the real-time audio
thread. Reading the live time source (polling a daemon, reading a device) is a
**blocking** operation and runs on a separate worker thread.
### Backends
| `NtpClock` | `std::time::SystemTime` (wall clock, ns) | Always (MVP default) |
| `PtpClock` | injectable `PtpTimeProvider` (PTPv2 daemon/NIC) | When PTP HW is present |
`NtpClock` is the always-available fallback. `PtpClock` reads PTP time from an
injectable provider (e.g. a daemon-polling thread reading `/dev/ptp*`); when no
provider is supplied it degrades to an `Unavailable` stub whose conversions
still work for offline mapping.
## Core types
| `ClockSource` | The public trait: `ptp_now_ns` / `sample_to_ptp` / `ptp_to_sample`. |
| `ClockAnchor` | The linear sample↔timestamp map (checked, overflow-safe `i128` math). |
| `NtpClock` | System wall-clock backend (default fallback). |
| `PtpClock` | PTPv2 backend with injectable `PtpTimeProvider`. |
| `PtpTimeProvider` | Trait for a live PTP timestamp source. |
| `ClockError` | Error enum (thiserror-backed). |
## Threading model
`ClockSource` is `Send` but **not** real-time-safe in general: `ptp_now_ns` may
block and must run off the RT audio thread. The pure conversions
`sample_to_ptp` / `ptp_to_sample` are allocation-free, never panic (return
`i64::MIN` on overflow), and are safe to call from the RT thread.
## Dependencies
| `audio-core-bsd` | 0.1.0 | `AudioFrame` (example only) | BSD-2-Clause |
| `thiserror` | 2.0 | `ClockError` derive | MIT OR Apache-2.0 |
| `proptest` (dev) | 1.11.0 | property tests | MIT OR Apache-2.0 |
This crate links **no system library**, so it builds and tests anywhere
(docs.rs, CI hosts without PTP hardware).
## Status
**0.x — experimental.** The API is not yet frozen. The `ClockSource` contract,
the `ClockAnchor` conversion, and both backends are implemented and tested.
Live PTP hardware timestamping depends on a `PtpTimeProvider` supplied by the
host (FreeBSD NIC support for igb/ixl/mlx5en is hardware-dependent).
- edition: 2021
- MSRV: 1.85
- license: BSD-2-Clause
## Example
Read the NTP clock and timestamp a few sample windows:
```rust
use audio_clock_bsd::{ClockSource, NtpClock};
let clock = NtpClock::new(48_000)?;
println!("now: {} ns", clock.ptp_now_ns()?);
// 48000 samples forward is exactly 1 second.
let one_sec_later = clock.sample_to_ptp(48_000);
# Ok::<(), audio_clock_bsd::ClockError>(())
```
See `examples/ntp_clock.rs` for a runnable version.
## License
BSD-2-Clause. See [`LICENSE`](./LICENSE).
[`ClockAnchor`]: https://docs.rs/audio-clock-bsd/latest/audio_clock_bsd/clock/struct.ClockAnchor.html