decodeSample method
Builds a message from a binary sample frame. Null for streams that do not carry samples.
Implementation
@override
IMessage? decodeSample(Uint8List frame) {
final channels = WsSampleFrame.decodeChannels(frame, config.channels);
final timestamp = DateTime.now();
// The frame carries the sender's clock at offset 6. Turning that into a
// transit time needs the sender's identity, which is why the subscription
// map keeps slot -> nodeUId: the offset is estimated per peer on the
// coordination stream, and this is where a data sample claims its share.
final peerUId = _slotOwners[WsSampleFrame.sourceSlotOf(frame)];
final offsets = clockOffsets;
final timing = MessageTiming(
sourceClock: WsSampleFrame.senderMicrosOf(frame) / 1e6,
// Null until the estimator has accepted a burst for this peer, which
// keeps transitSeconds null rather than reporting the difference of two
// unrelated monotonic clocks.
clockOffset: offsets?.offsetFor(peerUId),
uncertainty: offsets?.uncertaintyFor(peerUId),
receivedClock: PeerClock.now(),
sourceId: peerUId,
);
switch (config.dataType) {
case StreamDataType.float32:
case StreamDataType.double64:
return MessageFactory.double64Message(
data: IList(channels.map((v) => (v! as num).toDouble())),
channels: config.channels,
timestamp: timestamp,
timing: timing,
);
case StreamDataType.int8:
case StreamDataType.int16:
case StreamDataType.int32:
case StreamDataType.int64:
return MessageFactory.int64Message(
data: IList(channels.cast<int>()),
channels: config.channels,
timestamp: timestamp,
timing: timing,
);
case StreamDataType.string:
return MessageFactory.stringMessage(
data: IList(channels.cast<String>()),
channels: config.channels,
timestamp: timestamp,
timing: timing,
);
}
}