# Servers and Connected Devices in C# (AR51.Net)

See the **AR 51 server machines** and control them, and list the **devices** connected to the system — headsets, apps and phones.

## Server machines

`ar51.Servers.Servers` lists one entry per AR 51 machine and follows the system live; `ServersChanged` fires when a machine appears or disappears.

```csharp
foreach (ServerInfo server in ar51.Servers.Servers)
{
    ServerStatus status = await ar51.Servers.GetStatusAsync(server);
    Console.WriteLine($"{server.Name}: server {status.Server}, tracking {status.Tracking}, version {status.Version ?? "-"}");
}
```

Each machine has **two layers**: the **server program** and **tracking** inside it.

<div className="apiTable">

| Call | What it does |
|---|---|
| `LaunchServerAsync` | Launches the AR 51 server program. Does nothing if it's already running. |
| `QuitServerAsync` | Quits the program, letting it shut down cleanly. |
| `ForceQuitServerAsync` | Ends the program immediately — use it when `QuitServerAsync` doesn't work. |
| `RelaunchServerAsync` | Quits, waits a few seconds, and launches again. |
| `StartTrackingAsync` | Starts tracking. The server program must be running. |
| `StopTrackingAsync` | Stops tracking; the program keeps running. |

</div>

:::caution[These affect everyone using the system]
Each call acts on **one machine** — the `ServerInfo` you pass. But tracking runs on the server, not in your app, so quitting a machine's server program or stopping its tracking affects **every app connected to the AR 51 system** — Mocap Studio, Unity and Unreal apps, and other AR51.Net clients — not just yours.
:::

If a machine refuses with `Rejected` — for example "Restart too soon" — try again a few seconds later.

## Connected devices

`ar51.Devices.Devices` lists the apps and devices connected to the system — headsets, Unity and Unreal apps, phones and Mocap Studio — with their platform and battery level. It's read-only and follows the system live.

```csharp
foreach (DeviceInfo device in ar51.Devices.Devices)
    Console.WriteLine($"{device.Name}: {device.Type} ({device.Platform}), battery {device.BatteryPercent?.ToString() ?? "-"}%");
```

Both `ar51.Servers.Servers` and `ar51.Devices.Devices` are already filled when `StartAsync` returns. `DevicesChanged` fires when a device connects or disconnects, or a battery level changes. Battery levels refresh about every 10 seconds, so a device's `BatteryPercent` can be `null` at first. A skeleton's `DeviceId` matches the `Id` of the headset its person wears.

## Complete sample

Show every server machine with its status, then every connected device, and watch for devices connecting and disconnecting for 30 seconds. Read-only.

{/* SAMPLE:06-servers-and-devices — generated from the ar51-net-samples repo; edit there */}
```csharp title="Program.cs"
// Show every AR 51 server machine with its status, and every connected device. Read-only.
using AR51.Net;

await using IAR51Client ar51 = AR51Client.Create();
await ar51.StartAsync();

foreach (ServerInfo server in ar51.Servers.Servers)
{
    ServerStatus status = await ar51.Servers.GetStatusAsync(server);
    Console.WriteLine($"{server.Name} ({server.Host}): server {status.Server}, tracking {status.Tracking}, " +
                      $"uptime {status.Uptime?.ToString(@"hh\:mm\:ss") ?? "-"}, version {status.Version ?? "-"}");
}
// Control: LaunchServerAsync, QuitServerAsync, ForceQuitServerAsync, RelaunchServerAsync, StartTrackingAsync, StopTrackingAsync.

foreach (DeviceInfo device in ar51.Devices.Devices)
    Console.WriteLine($"{device.Name}: {device.Type} ({device.Platform}) at {device.Host}, battery {device.BatteryPercent?.ToString() ?? "-"}%");

ar51.Devices.DevicesChanged += (_, e) =>
{
    foreach (DeviceInfo device in e.Added) Console.WriteLine($"+ {device.Name} connected");
    foreach (DeviceInfo device in e.Removed) Console.WriteLine($"- {device.Name} disconnected");
};
Console.WriteLine("Watching devices for 30 s...");
await Task.Delay(TimeSpan.FromSeconds(30));
```

[View this sample on Bitbucket](https://bitbucket.org/ar51/ar51-net-samples/src/main/06-servers-and-devices/) — clone the [samples repository](https://bitbucket.org/ar51/ar51-net-samples) to run it.
{/* /SAMPLE */}

## Reference

[`IServerClient`](/docs/sdk-api/csharp-api/classes/iserverclient/) · [`ServerStatus`](/docs/sdk-api/csharp-api/classes/iserverclient/#serverstatus) · [`IDeviceClient`](/docs/sdk-api/csharp-api/classes/ideviceclient/) · [`DeviceInfo`](/docs/sdk-api/csharp-api/classes/ideviceclient/#deviceinfo)
