Sync client
Synchronization protocol implementations extend SyncClient to connect playback
observations and controls with a synchronized session.
Implementation responsibilities
Each implementation supplies these methods:
| Operation | Responsibility |
|---|---|
getNetClient() |
Return the transport client used for protocol communication. |
login(username, room, password) |
Implement the protocol’s login and room-joining behavior. |
getRoomInfo() |
Return the room name and participant list as RoomInfo. |
onStatusChange(status) |
Handle observed local playback changes and decide what to send. |
handleResponse(data) |
Interpret incoming protocol messages and apply their effects. |
sendKeepAlive() |
Supply the protocol’s periodic keep-alive communication. |
The constructor passes a PlayerManager and a keep-alive interval in milliseconds to the
base class. The implementation supplies its transport and codec, then calls
connect(host, port, codec) to establish communication.
Working with playback state
The base class exposes its supplied PlayerManager for playback observations and controls.
The implementation decides how to filter local changes, represent them as messages, and
interpret incoming updates. Any expected state used to track what the server expects belongs to the
protocol implementation; the base class does not maintain it.
See Player management in Core for observation and control behavior, and Coordination for the flow between components.
Room information
RoomInfo contains a room name and a list of users. The implementation maintains this
information as participants join and leave. The base class does not store membership
information or interpret room messages.
Sending and receiving
Use the inherited send(data) method for outgoing messages so successful sends update the
base class’s keep-alive tracking. Incoming decoded messages reach handleResponse(data)
through the listener registered by connect().
Network responses, local state callbacks, and scheduled keep-alives can run on different threads. Implementations need to coordinate access to their own shared state.
See Establishing a connection for how Core selects and starts a synchronization implementation.
Client management in Core
This section describes the behavior supplied by the base class for contributors working on SyncNuke Core.
Connection and message dispatch
connect() delegates connection setup to getNetClient() with the host, port, and codec,
then registers handleResponse() as a receive listener. The transport performs encoding
and decoding through that codec.
send() ignores null messages. For other messages, it delegates to the transport and records
the current time after the send returns successfully. A failed send does not update that
timestamp; the exception propagates to the caller.
Keep-alive scheduling
A positive constructor interval schedules checks at that interval, with the first check occurring after one interval. Zero or a negative interval disables scheduling.
At each check, the base class compares the current time with the last successful outgoing
send. Once the elapsed time reaches the interval, it calls sendKeepAlive(). Incoming
messages do not reset this timer. The callback defines the message to send; for example,
DataSaver sends a projected playback state.
The base class catches and logs exceptions from the scheduled callback so later checks can
continue. getCurrentTime() obtains milliseconds from the supplied TimingService; the
constructor overload accepting that service allows timing to be controlled in tests.
Releasing resources
close() cancels the keep-alive task and closes the transport, logging exceptions from
transport cleanup. An implementation with protocol-specific departure messages or resources
can override close() and call super.close() to retain the base cleanup.
Closing a sync client does not close its supplied player manager. See Lifecycle for how Core manages their lifetimes.
Reference material
SyncNuke Core’s SyncClient and RoomInfo.
DataSaverClient provides a concrete synchronization implementation.