ServiceManager
public sealed class ServiceManager : Singleton<ServiceManager>
Inherits: Singleton<ServiceManager> — a MonoBehaviour base. Reach the live instance with ServiceManager.Instance.
The connection entry-point of the SDK. Drop one on a GameObject and it stands up the SDK's local service host, performs discovery, and tracks which remote components (CVS, calibration, camera feed, etc.) are connected. It connects on Start() — there is no public Connect() — so placing the component in the scene (with discovery succeeding) is what establishes the connection. Once started, reach the live connection through the static Server. Connection state is exposed through static properties so any code can poll it without holding a reference.
The AR 51 Unity SDK works in meters (positions/lengths) and degrees (angles). ServiceManager itself is connection plumbing and exposes no spatial values, but everything it connects you to (skeletons, cameras, objects) reports meters.
This page is reference (facts only). For the step-by-step connect → skeleton → character walkthrough, see the How-to guide.
Properties
Static connection state
These are static — poll them from anywhere to gate service-dependent logic.
| Property | Type | Access | Description |
|---|---|---|---|
| Connection | |||
Server | ServiceContainer | get (private set) | the running server/connection container (transport assembly); null until startup completes. Use it to reach SkeletonProvider, ConnectedComponents, GetCameraFeedClient, etc. |
IsConnected | bool | get | true when the underlying server is up and connected — poll this first before issuing service calls |
IsCvsConnected | bool | get | true when at least one main CVS server component is in the connected set; gate skeleton-dependent UI/logic on this |
IsCalibrationConnected | bool | get | true when a CVS calibration component is connected |
Inspector configuration
Set these in the Inspector (or in code before Start) to configure discovery, ports, platform identity, and whether this instance acts as a dedicated game server (DGS).
| Field | Type | Default | Description |
|---|---|---|---|
| Logging | |||
LogRequests | bool | false | verbose request logging |
| Dispatch | |||
MaxQueueSize | int | 100 | Unity-thread dispatch queue cap |
| Identity | |||
Platform | PlatformType | — | auto-set to the running platform |
HandProvider | HandProviderType | — | which hand-tracking provider to use |
BatteryLevel | float | 0 | -1 = use system battery; 0..100 override |
| Dedicated game server | |||
IsDedicatedGameServer | bool | false | run this instance as a DGS |
DedicatedOmsAddress | string | "" | explicit OMS address for DGS |
| Discovery & ports | |||
DiscoveryPort | int | — | UDP discovery port |
UseRandomServicePort | bool | true | pick a free TCP port for the local service |
ServicePort | int | — | explicit local service port when UseRandomServicePort is false |
RunOMS | bool | false | host an embedded OMS in-process |
KeepAliveTimeoutInMillis | int | — | livelihood / keep-alive timeout (ms) |
Timeline override (advanced / playback)
| Member | Type | Access | Description |
|---|---|---|---|
EnqueueTimeSeconds | double | get | current enqueue clock (seconds) |
OverrideTimeSeconds | double | field | overridden clock value; leave at the -1 default for live use |
OverrideTimeDelaySeconds | double | field | added delay against the overridden clock |
The timeline-override surface (OverrideTimeSeconds, EnqueueDelayedMessages, IsEnqueueRequired) is intended primarily for internal playback timing, not general app use. Most callers leave the override fields at their -1 defaults.
Method summary
Static — discovery
| Method | Returns | |
|---|---|---|
GetMainServerComponents | IEnumerable<ComponentDescriptor> | static |
FindComponentByService | ComponentDescriptor | static |
FindComponentsByService | ComponentDescriptor[] | static |
WaitForService | Task<ComponentDescriptor[]> | static · async |
Instance — connection control
| Method | Returns | |
|---|---|---|
Reconnect | void | |
Disconnect | void |
Instance — timeline (advanced)
| Method | Returns | |
|---|---|---|
IsEnqueueRequired | bool | ⚠️ playback |
EnqueueDelayedMessages | void | ⚠️ playback |
→ Full descriptions in Method details below.
Events
Standard .NET events (subscribe with +=). Bind these on the instance (ServiceManager.Instance).
| Event | Signature | Fires when |
|---|---|---|
OnStarted | EventHandler OnStarted | the service host has started and Server is available — the signal that the connection is up |
OnRegistrationChanged | EventHandler OnRegistrationChanged | the set of connected/registered components changes (a component joined or left) — subscribe to refresh your component list |
Method details
GetMainServerComponents
public static IEnumerable<ComponentDescriptor> GetMainServerComponents();
The connected CVS server components.
FindComponentByService
public static ComponentDescriptor FindComponentByService(string serviceName);
Find the first connected component advertising a given service name. Use the returned descriptor's Ip / Port / GetEndpoint() to connect.
var cam = ServiceManager.FindComponentByService(ServiceNames.CameraFeedService);
if (cam != null)
{
var feed = ServiceManager.Server.GetCameraFeedClient(cam.Ip, cam.Port);
// … register a listener on `feed`
}
FindComponentsByService
public static ComponentDescriptor[] FindComponentsByService(string serviceName);
Find all connected components advertising a given service name.
WaitForService
public static async Task<ComponentDescriptor[]> WaitForService(
string serviceName,
CancellationToken token = default,
float millisecondsTimeout = float.MaxValue);
Awaitable discovery: polls until a component offering serviceName appears (or the token cancels / the timeout elapses), then returns all matching components. Call this after the manager has started to wait for a CVS/skeleton service to come online, instead of polling FindComponentByService yourself.
default (no cancellation)float.MaxValue (wait indefinitely)// Wait (up to 5 s) for the skeleton service after the manager starts, then read its endpoint.
async void Start()
{
ServiceManager.Instance.OnStarted += async (s, e) =>
{
var components = await ServiceManager.WaitForService(
ServiceNames.SkeletonService,
this.GetCancellationTokenOnDestroy(), // ⚠️ cancellation source depends on your setup
millisecondsTimeout: 5000f);
if (components.Length == 0)
Debug.LogWarning("Skeleton service did not come online in time");
else
Debug.Log($"Skeleton service at {components[0].GetEndpoint()}");
};
}
Reconnect
public void Reconnect();
Resume the connection (restarts the server). Internally tied to application-pause handling — the SDK calls it when the app resumes — but you can call it after a manual Disconnect.
Disconnect
public void Disconnect();
Pause the connection by shutting the server down and stopping discovery. Pair with Reconnect to bring it back. There is no public Connect() — the initial connection happens automatically on Start().
IsEnqueueRequired
public bool IsEnqueueRequired(double timestamp);
Whether an incoming message at timestamp must be queued against the overridden clock rather than dispatched immediately.
true if the message should be enqueued for delayed dispatchPart of the internal playback-timing surface; not intended for general app use.
EnqueueDelayedMessages
public void EnqueueDelayedMessages(double timestamp, Action action, string caller = null);
Queue action to run when the overridden clock reaches timestamp.
Part of the internal playback-timing surface; not intended for general app use.
See also
ServiceNames— the service-name constants to pass to the discovery methodsComponentDescriptor— the discovered-component descriptor (Ip/Port/GetEndpoint()) these methods returnSkeletonConsumer— the core consumer that drives characters onceServiceManageris connectedCameraFeedClient— obtained viaServiceManager.Server.GetCameraFeedClient(...)- Class index — all Unity SDK types
- How-to: connect → drive a character