Skip to content

0.9.0

Latest

Choose a tag to compare

@lhoward lhoward released this 05 Oct 22:16
· 64 commits to main since this release

0.9.0

Changes since 0.8.5.

Highlights

  • OCP.2 (AES70-4, JSON) on controller and device, over WebSocket and datagrams (including Network.framework). Parameter and event-data names follow the AES70-2A model and are checked against it; events reach a subscriber already parsed, and can be decoded on the client.
  • Connection Management 4: controller and device classes, shared helpers (typed blobs, MAC addresses, counter sets), and the Milan (AES70-22), AES67 and Dante adaptations, following the 2026-09-16 and 2026-09-19 AES70-21 drafts.
  • Methods declared once: @OcaMethod / @OcaDeviceMethod generate one method descriptor that drives the client's invoke and the device's dispatch. Every class is converted, with the model's names, and guarded by golden statuses, a descriptor sweep and a check of the model's spelling.

Device

  • Notifications raised in one scope are sent together, fanned out to controllers concurrently, and delivered only to controllers subscribed to that event; event parameters are encoded only when someone will receive them, once per controller.
  • Setting a device property to the value it already has no longer notifies.
  • Every controller's subscriptions are kept in the subscription manager.
  • A notification's recipient can read its event and event data, and a property change's property ID, without decoding the value (SPI).
  • Datasets: storage providers can cap a dataset's size and total storage; SQLite datasets are listed without loading their contents; FindDatasetsRecursive is answered; a block on a device without dataset storage answers dataset queries with no datasets.
  • A command with too few or malformed parameters is answered with its status, not a decoding failure.
  • A group's lock is checked before the members a command names are resolved.
  • ClearResetCause and the Device Reset message are implemented.
  • The device manager's Managers lists every registered manager; default object roles have no spaces.
  • A device property belongs to the class its ID names, not to its depth in the lineage; a vector property is described with both its property IDs; the value type is valueType.
  • Other packages can enumerate a device object's properties, tell the device a controller has gone, and register, browse and resolve DNS-SD services of any type.

Controller

  • OcaMediaClock3.setCurrentRate(rate:) sets a media clock's rate and keeps its time source.
  • Connection broker: a client can choose how each device's connection is made, and the default is public; device opens are single-flight; resetBrowsing; a service is resolved before it is added and given up on after 5 s; each service a browser finds is handled in its own task; DNS-SD removals are a hint, not a fact.
  • Connecting does not block, so one dead candidate cannot use up the budget; IP literals resolve numerically, so NAT64 cannot rewrite them; hostnames resolve on Windows.
  • Requests time out on one timer per connection.
  • The well-known proxies go through the object registry, and the controller classes the device registry knows are registered.

Transport and protocol

  • The OCP.1 Codable coder is rewritten; PDUs are encoded in one pass into exact-size Data.
  • Framing and lifecycle hardening across stream, datagram, WebSocket, CFSocket, OpenSSL and Mach transports: writes serialised per connection, one PDU reader per connection, read watchdogs, stale socket files unlinked before binding, empty datagrams ignored.
  • WebSocket: the advertised path is honoured; an upgrade naming only control protocols the path does not serve is refused; an endpoint can serve other routes beside its control protocols; AES70-3 §8.4.3.4 is followed.
  • Several messages for a packet transport are divided into PDUs that fit.
  • Non-finite numbers are represented in JSON as strings.
  • TXT records are registered with txtvers and protovers first.

Fixes

  • OcaMatrix: real size bounds, all six values of GetSize, locking as AES70-2 specifies, SetCurrentXY keeps the prior lock state, currentMembers is a property.
  • OcaFilterArbitraryCurve sends its transfer function as three parameters; OcaStringSensor has the AES70-2 shape; OcaTemperatureSensor's reading and OcaMediaTransportNetwork's alignment level and gain are bounded.
  • 2D arrays are emitted and indexed in storage order.
  • A malformed MAC address is rejected instead of losing octets.
  • The AES70-2024 busy status is added.
  • A Swift SIL optimiser miscompile is avoided by casting decoder metatypes out of line.
  • Darwin: the Mach listener port is destroyed when the endpoint stops; SwiftOCAUI and Network.framework isolation warnings are cleaned up.

Breaking changes

  • Dual-protocol types are Oca, not Ocp1: Ocp1Parameters → OcaParameters; the connection, endpoint and controller types Ocp1… → Oca…; Ocp1MessageBatcher → OcaMessageBatcher.
  • Ocp1Error.notImplemented is removed in favour of the .notImplemented status.
  • OcaClassID(parent:_:) takes the parent first; a proprietary class ID's authority is not a level in defLevel.
  • OcaInterval is inclusive.
  • Parameter records are renamed after the AES70-2A model.
  • Classes declare their methods with @OcaMethod / @OcaDeviceMethod; subclasses that override method handling should use the method tables.
  • The provisional Dante application adaptation data is replaced by the drafts' types.
  • Requires Swift 6.3 or later (IORingSwift 2.0.0), upstream sideeffect-io AsyncExtensions 0.7 instead of the fork, and swift-binary-parsing 0.0.2 (which still pins swift-syntax 602).

Tooling

  • OCAPerfBench compares OCP.1 and OCP.2.
  • ocp2-nc.sh dumps a device's whole hierarchy.
  • The Xcode project builds only the OCABrowser app, with the libraries from the package.