dxd - dynax driver framework 3.0.2
cross platform open source driver development framework
Loading...
Searching...
No Matches
Clock design (future): clocks as entities of their own
Todo
A group ticks one thread from a source that is either free running or signalled by whoever holds an abstract::event to it, and which of the two it gets is answered in code rather than by the desc: a bus device's stream::device::hw_clock() override, and the hw_clock(event&, iosize) try/catch in engine::group::initialize() choosing between a device clock and the system clock. The transport - who moves the data in front of a ring - is declared by the desc (dxd/CLAUDE.md, "A ring has two sides and at most one transport"); the clock is the axis this page describes.

A clock is an object with an origin: a device (its hw clock), a bus (the USB frame counter), a stream (an endpoint's IO callback, e.g. a CoreAudio IOProc), or something outside the device altogether (word clock, another interface, the far end of an interconnect, a network). Clocks therefore live in a registry outside the device - not in the device's own domain device.hw - to which devices, buses and streams publish theirs. A clock domain (desc::clock, stream::config::clock::domain) selects exactly one clock via clocksource, whatever its origin; the domain's group derives its tick source from that clock: free running for a synthetic origin (period interval(samplerate, granularity)), the clock's event otherwise. Master/slave is nothing more than which clock a domain selected; a domain slaved to a foreign clock takes that clock's rate along, and an incompatible selection is refused, never resampled.

The clock is independent of the transport, which is what makes the mixed cases representable:

  • virtual alone: synthetic clock, no transport.
  • virtual slaved to a CoreAudio interface: that interface's IOProc clock, from outside the device, still without a transport.
  • CoreAudio bidirectional: its own IOProc's stream clock, the HAL as transport.
  • CoreAudio unidirectional with the far end as slave: the IOProc clock published outward, the far end selects it.
  • CoreAudio as slave (the pod session): an external clock; the HAL stays the transport, its zero timestamps follow that clock instead of synthesizing one.
  • USB on word clock: an external clock, the pipe stays the transport.

Open: the clock id namespace across device boundaries (who issues it, does it persist in the desc), how a slave adopts the master's rate, and what an external clock delivers to a group - the tick event only, or timestamps and frame counters as usb::stream::group::sync takes them from the bus frame.