# ServiceManager

<Badge tone="type">sealed class</Badge> <Badge>Unity component</Badge> <Badge>singleton</Badge> <Badge>static</Badge>

```csharp
public sealed class ServiceManager : Singleton<ServiceManager>
```

**Inherits:** [`Singleton<ServiceManager>`](/docs/sdk-api/unity-api/connection) — 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.

:::note[Units]
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.
:::

:::tip[How-to]
This page is **reference** (facts only). For the step-by-step *connect → skeleton → character* walkthrough, see the [How-to guide](/docs/sdk-api/unity-api/skeletons-and-characters).
:::

## Properties

### Static connection state

These are `static` — poll them from anywhere to gate service-dependent logic.

<div className="apiPropTable">

| Property | Type | Access | Description |
|---|---|---|---|
| **Connection** | | | |
| `Server` | [`ServiceContainer`](/docs/sdk-api/unity-api/connection) | `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 |

</div>

### 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).

<div className="apiPropTable">

| Field | Type | Default | Description |
|---|---|---|---|
| **Logging** | | | |
| `LogRequests` | `bool` | `false` | verbose request logging |
| **Dispatch** | | | |
| `MaxQueueSize` | `int` | `100` | Unity-thread dispatch queue cap |
| **Identity** | | | |
| `Platform` | [`PlatformType`](/docs/sdk-api/unity-api/connection) | — | auto-set to the running platform |
| `HandProvider` | [`HandProviderType`](/docs/sdk-api/unity-api/hands-controllers-boundary) | — | 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) |

</div>

### Timeline override (advanced / playback)

<div className="apiPropTable">

| 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 |

</div>

:::caution[⚠️ needs confirmation]
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`](#getmainservercomponents) | `IEnumerable<ComponentDescriptor>` | <Badge>static</Badge> |
| [`FindComponentByService`](#findcomponentbyservice) | [`ComponentDescriptor`](/docs/sdk-api/unity-api/connection) | <Badge>static</Badge> |
| [`FindComponentsByService`](#findcomponentsbyservice) | `ComponentDescriptor[]` | <Badge>static</Badge> |
| [`WaitForService`](#waitforservice) | `Task<ComponentDescriptor[]>` | <Badge>static</Badge> · async |

**Instance — connection control**

| Method | Returns | |
|---|---|---|
| [`Reconnect`](#reconnect) | `void` | |
| [`Disconnect`](#disconnect) | `void` | |

**Instance — timeline (advanced)**

| Method | Returns | |
|---|---|---|
| [`IsEnqueueRequired`](#isenqueuerequired) | `bool` | ⚠️ playback |
| [`EnqueueDelayedMessages`](#enqueuedelayedmessages) | `void` | ⚠️ playback |

→ Full descriptions in [Method details](#method-details) below.

## Events

Standard .NET `event`s (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

<ApiBody kind="method" tags="static">

```csharp
public static IEnumerable<ComponentDescriptor> GetMainServerComponents();
```

The connected CVS server components.

<Returns type="IEnumerable<ComponentDescriptor>" typeHref="/docs/sdk-api/unity-api/connection#componentdescriptor">the main CVS server components, empty when none are connected</Returns>

</ApiBody>

### FindComponentByService

<ApiBody kind="method" tags="static">

```csharp
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.

<Params>
<Param name="serviceName" type="string">a service name constant from [`ServiceNames`](/docs/sdk-api/unity-api/connection#servicenames) (e.g. `ServiceNames.SkeletonService`)</Param>
</Params>

<Returns type="ComponentDescriptor" typeHref="/docs/sdk-api/unity-api/connection#componentdescriptor">the first matching component, or `null` if none is connected</Returns>

<Example inferred>

```csharp
var cam = ServiceManager.FindComponentByService(ServiceNames.CameraFeedService);
if (cam != null)
{
    var feed = ServiceManager.Server.GetCameraFeedClient(cam.Ip, cam.Port);
    // … register a listener on `feed`
}
```

</Example>

</ApiBody>

### FindComponentsByService

<ApiBody kind="method" tags="static">

```csharp
public static ComponentDescriptor[] FindComponentsByService(string serviceName);
```

Find **all** connected components advertising a given service name.

<Params>
<Param name="serviceName" type="string">a service name constant from [`ServiceNames`](/docs/sdk-api/unity-api/connection#servicenames)</Param>
</Params>

<Returns type="ComponentDescriptor[]" typeHref="/docs/sdk-api/unity-api/connection#componentdescriptor">every matching component, or an empty array if none is connected</Returns>

</ApiBody>

### WaitForService

<ApiBody kind="method" tags="static, async">

```csharp
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`](#findcomponentbyservice) yourself.

<Params>
<Param name="serviceName" type="string">a service name constant from [`ServiceNames`](/docs/sdk-api/unity-api/connection#servicenames)</Param>
<Param name="token" type="CancellationToken">cancels the wait early; defaults to `default` (no cancellation)</Param>
<Param name="millisecondsTimeout" type="float">give-up time in milliseconds; defaults to `float.MaxValue` (wait indefinitely)</Param>
</Params>

<Returns type="Task<ComponentDescriptor[]>" typeHref="/docs/sdk-api/unity-api/connection#componentdescriptor">all components offering the service once one appears; an empty array if the timeout elapses or the token cancels first</Returns>

<Example inferred>

```csharp
// 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()}");
    };
}
```

</Example>

</ApiBody>

### Reconnect

<ApiBody kind="method" tags="instance">

```csharp
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).

</ApiBody>

### Disconnect

<ApiBody kind="method" tags="instance">

```csharp
public void Disconnect();
```

Pause the connection by shutting the server down and stopping discovery. Pair with [`Reconnect`](#reconnect) to bring it back. There is no public `Connect()` — the initial connection happens automatically on `Start()`.

</ApiBody>

### IsEnqueueRequired

<ApiBody kind="method" tags="instance">

```csharp
public bool IsEnqueueRequired(double timestamp);
```

Whether an incoming message at `timestamp` must be queued against the overridden clock rather than dispatched immediately.

<Params>
<Param name="timestamp" type="double">a message timestamp, seconds since the Unix epoch</Param>
</Params>

<Returns type="bool">`true` if the message should be enqueued for delayed dispatch</Returns>

:::caution[⚠️ needs confirmation]
Part of the internal playback-timing surface; not intended for general app use.
:::

</ApiBody>

### EnqueueDelayedMessages

<ApiBody kind="method" tags="instance">

```csharp
public void EnqueueDelayedMessages(double timestamp, Action action, string caller = null);
```

Queue `action` to run when the overridden clock reaches `timestamp`.

<Params>
<Param name="timestamp" type="double">target dispatch time, seconds since the Unix epoch</Param>
<Param name="action" type="Action">work to run at that time</Param>
<Param name="caller" type="string">optional diagnostic label for the caller</Param>
</Params>

:::caution[⚠️ needs confirmation]
Part of the internal playback-timing surface; not intended for general app use.
:::

</ApiBody>

## See also

- [`ServiceNames`](/docs/sdk-api/unity-api/connection#servicenames) — the service-name constants to pass to the discovery methods
- [`ComponentDescriptor`](/docs/sdk-api/unity-api/connection) — the discovered-component descriptor (`Ip` / `Port` / `GetEndpoint()`) these methods return
- [`SkeletonConsumer`](/docs/sdk-api/unity-api/classes/skeletonconsumer) — the core consumer that drives characters once `ServiceManager` is connected
- [`CameraFeedClient`](/docs/sdk-api/unity-api/classes/camerafeedclient) — obtained via `ServiceManager.Server.GetCameraFeedClient(...)`
- [Class index](/docs/sdk-api/unity-api/classes) — all Unity SDK types
- How-to: [connect → drive a character](/docs/sdk-api/unity-api/skeletons-and-characters)
