---
sidebar_position: 0
---

# sync

The `sos.sync` API groups together methods for synchronization of multiple devices. Devices are synchronized either through an external
server or one of the devices becomes a master device.

## Methods

### broadcastValue()

The `broadcastValue()` method sends a key-value pair to all other devices in a specified group.

```ts expandable
broadcastValue({ groupName, key, value }: {
    groupName?: string;
    key: string;
    value: any;
}): Promise<void>;
```

#### Params

| Name        | Type     | Required         | Description                                                                     |
|-------------|----------|------------------|---------------------------------------------------------------------------------|
| `groupName` | `String` |  <div>Yes</div>  | The name of the group to broadcast the value to. Defaults to the default group. |
| `key`       | `String` |  <div>Yes</div>  | The key to broadcast the value under.                                           |
| `value`     | `any`    |  <div>Yes</div>  | The value to broadcast. It can be any valid type                                |

#### Return value

A promise that resolves when the value is broadcasted.

#### Possible errors


- Error If the group name is not a string.
- Error If the key is not a string.
- Error If the value is not a valid type (e.g. object, array, etc.).
- Error If unable to broadcast the value.
- Error If the value can't be sent

#### Example

```ts
// broadcast a value to all devices in the group
await sos.sync.broadcastValue({
	groupName: 'my-group',
	key: 'my-key',
	value: 'my-value',
});

// Received on the other devices:
sos.sync.onValue((key, value, groupName) => {
	console.log(`Received value for key ${key} in group ${groupName}:`, value);
});
```

<Separator />

### cancelWait()

The `cancelWait()` method aborts a wait on all devices in a group. Sometimes it's necessary to cancel a pending wait. One such
situation would be when the group has to make a sudden change in content or another behavior but there's a risk that part of the group
already called wait() and is waiting for the rest but the rest will never call it at this point. In order to gracefully clean up any
pending activity, use this method.

:::warning
Any pending wait will be canceled and the promise will be rejected with an error.
:::

```ts expandable
cancelWait(groupName?: string): Promise<void>;
```

#### Params

| Name        | Type     | Required        | Description                                                                  |
|-------------|----------|-----------------|------------------------------------------------------------------------------|
| `groupName` | `string` |  <div>No</div>  | The name of the group to cancel the wait for. Defaults to the default group. |

#### Return value

A promise that resolves when the wait is canceled.

#### Possible errors


- Error If the group name is not a string.
- Error If unable to cancel the wait.
- Error If any other error occurs during canceling the wait.

#### Example

```ts
sos.sync.wait('someData', 'someRandomNameGroup').catch((err) => {
    // this will happen once cancelWait is called
    console.error('wait failed', err);
});

// this will cause above wait promise to reject
await sos.sync.cancelWait('someRandomNameGroup');
```

<Separator />

### close()

The `close()` method disconnects the device from synchronization server and other devices. Recommended to call this method after the
synchronization is not required any longer.

```ts expandable
close(): Promise<void>;
```

#### Return value

A promise that resolves when the connection is closed.

#### Possible errors

Error If unable to close the connection.

<Separator />

### connect(options)

The `connect()` method initializes the device and connects it to the rest of the devices. This initializes the connection and is
mandatory to call, since synchronization is an optional feature and doesn’t get initialized by default to save resources and bandwidth.
You can optionally specify a custom sync server URI in case you are running the sync server in a custom location.

:::info
All devices, that should be synchronized together, must select the same engine. Otherwise, they won't be able to communicate with each
other.
:::

```ts expandable
connect(options?: SynchronizationEngineOptions): Promise<void>;
// show-more
type SynchronizationEngineOptions = ConnectSyncServerOptions | ConnectP2PLocalOptions | ConnectUdpOptions;

/**
 * Options for sync-server synchronization.
 */
interface ConnectSyncServerOptions {
    engine?: SyncEngine.SyncServer;
    uri?: string;
}

/**
 * The `SyncEngine` enum defines the available synchronization engines that can be used to synchronize devices.
 * Each engine has its own method of connecting devices and synchronizing data.
 */
enum SyncEngine {
    /** Use external sync server. Device will connect to the server via websocket. */
    SyncServer = "sync-server",
    /** Synchronize directly with other devices in the local network via UDP and TCP. */
    P2PLocal = "p2p-local",
    /**
     * Synchronize directly with other devices in the local network via UDP.
     * @deprecated use {@link P2PLocal}
     */
    Udp = "udp"
}

/**
 * Options for P2P local synchronization.
 */
interface ConnectP2PLocalOptions {
    engine: SyncEngine.P2PLocal;
}

/** @deprecated use SyncEngine.P2PLocal and ConnectP2PLocalOptions */
interface ConnectUdpOptions {
    engine: SyncEngine.Udp;
}

```

#### Params

| Name             | Type                           | Required         | Description                                                                                                    |
|------------------|--------------------------------|------------------|----------------------------------------------------------------------------------------------------------------|
| `options.engine` | `SynchronizationEngineOptions` |  <div>Yes</div>  | Synchronization engine to use.                                                                                 |
| `options.uri`    | `string`                       |  <div>No</div>   | Address of the sync server engine. Only relevant for sync-server. If omitted, the default server will be used. |

#### Return value

A promise that resolves when the connection is established.

#### Possible errors


- Error If unable to connect.
- Error If the `uri` is not a valid URL when using the sync-server engine.
- Error If the `engine` is not a valid synchronization engine.
- Error If any other error occurs during connection.

#### Example

```ts
// use default engine
await sos.sync.connect();

// use sync-server engine and default server
await sos.sync.connect({ engine: 'sync-server' });

// use sync-server engine and custom server
await sos.sync.connect({ engine: 'sync-server', uri: syncServerUri });

// use p2p-local engine
await sos.sync.connect({ engine: 'p2p-local' });
```

:::note[GitHub Example]

- [ How to use synchronizer in applet](https://github.com/signageos/applet-examples/tree/master/examples/content-js-api/sync-video)
- [ How to synchronize mixed content](https://github.com/signageos/applet-examples/tree/master/examples/content-js-api/sync-mixed-content)

:::

<Separator />

### isMaster()

Returns true if the device is currently the master of the group.

```ts expandable
isMaster(groupName?: string): Promise<boolean>;
```

#### Params

| Name        | Type     | Required        | Description                                                               |
|-------------|----------|-----------------|---------------------------------------------------------------------------|
| `groupName` | `string` |  <div>No</div>  | The group name to check for master status. Defaults to the default group. |

#### Return value

A promise that resolves with true if the device is the master, false otherwise.

<Separator />

### joinGroup()

The `joinGroup()` method joins a group of other devices. This method has to be called after `connect()` call. Before any communication
takes place, all participating devices have to be connected and recognize one another. Recommended to call this method early.

```ts expandable
joinGroup(options: {
    groupName?: string;
    deviceIdentification?: string;
}): Promise<void>;
```

#### Params

| Name      | Type                                                                               | Required         | Description                  |
|-----------|------------------------------------------------------------------------------------|------------------|------------------------------|
| `options` | `{ groupName?: string \| undefined; deviceIdentification?: string \| undefined; }` |  <div>Yes</div>  | Options for joining a group. |

#### Return value

A promise that resolves when the device joins the group.

#### Possible errors


- Error If the group name is not a string.
- Error If the device identification is not a string.
- Error If unable to join the group.
- Error If any other error occurs during joining the group.

#### Example

```ts
await sos.sync.connect();
await sos.sync.joinGroup({ groupName: 'my-group', deviceIdentification: 'my-device-id' });
```

:::note[GitHub Example]

- [ How to use synchronizer in applet](https://github.com/signageos/applet-examples/tree/master/examples/content-js-api/sync-video)

:::

<Separator />

### leaveGroup()

The `leaveMethod` method leaves a group of devices.

```ts expandable
leaveGroup(groupName?: string): Promise<void>;
```

#### Params

| Name        | Type     | Required        | Description                                                    |
|-------------|----------|-----------------|----------------------------------------------------------------|
| `groupName` | `string` |  <div>No</div>  | The name of the group to leave. Defaults to the default group. |

#### Return value

A promise that resolves when the device leaves the group.

#### Possible errors


- Error If the group name is not a string.
- Error If unable to leave the group.
- Error If any other error occurs during leaving the group.

#### Example

```ts
await sos.sync.leaveGroup('my-group');
```

<Separator />

### onClosed()

The `onClosed()` method sets up a listener, which is called whenever the device is disconnected from the sync. If it closed because
`close()` was called, it will emit without any arguments. if it closed because of an error, it will emit with an error object as the
first argument.

```ts expandable
onClosed(listener: (error?: Error) => void): void;
```

#### Params

| Name       | Type                                   | Required         | Description                                            |
|------------|----------------------------------------|------------------|--------------------------------------------------------|
| `listener` | `(error?: Error \| undefined) => void` |  <div>Yes</div>  | The listener function to call when the sync is closed. |

#### Return value

Returns when listener is set up.

#### Possible errors

Error If the listener is not a function.

<Separator />

### onStatus()

The `onStatus()` method sets up a listener, which is called periodically or whenever there is a change (i.e. new device
connects/disconnects to/from the group).

```ts expandable
onStatus(listener: (status: StatusEvent) => void): void;
// show-more
interface StatusEvent {
    groupName?: string;
    /** Array of device identifications connected to the group. */
    connectedPeers: string[];
    /** True if this device is currently master of the group (this may change over time). */
    isMaster: boolean;
}

```

#### Params

| Name       | Type                            | Required         | Description                                            |
|------------|---------------------------------|------------------|--------------------------------------------------------|
| `listener` | `(status: StatusEvent) => void` |  <div>Yes</div>  | The listener function to call when the status changes. |

#### Return value

Returns when listener is set up.

#### Possible errors

Error If the listener is not a function.

<Separator />

### onValue()

The `onValue()` method sets up a listener, which is called whenever the device receives a broadcasted message.

```ts expandable
onValue(listener: (key: string, value: any, groupName?: string) => void): void;
```

#### Params

| Name       | Type                                                                 | Required         | Description                                                |
|------------|----------------------------------------------------------------------|------------------|------------------------------------------------------------|
| `listener` | `(key: string, value: any, groupName?: string \| undefined) => void` |  <div>Yes</div>  | The listener function to call when a value is broadcasted. |

#### Return value

Returns when listener is set up.

#### Possible errors

Error If the listener is not a function.

<Separator />

### removeEventListeners()

The `removeEventListeners()` method removes all listeners set up on `sos.sync` object.

```ts expandable
removeEventListeners(): void;
```

<Separator />

### wait()

The `wait()` method synchronizes with other devices by waiting for other devices before proceeding.

One way to synchronize devices is to make them wait for each other at a certain moment. This would be most commonly used before the
device hits “play” on a video, to make it wait for other devices so they all start playing the video at the same time.

This method returns a promise that resolves once all the devices meet and are ready to continue together. Any action that results in
visible synchronized behavior should be triggered immediately after and any related background preparations should be called before to
prevent delays.

Sometimes devices might go out of sync due to unpredictable conditions like loss of internet connection. To ensure re-sync of an out of
sync device, you can pass some data as the first argument. This can be any data that informs the whole group about what content is
about to play next. Once all devices are ready, data from the master device is passed to everyone and the rest of the data is ignored.
Therefore, when implementing your applet you should rely on the result data and not the data that is passed to the wait method as an
argument.

```ts expandable
wait(data?: any, groupName?: string, timeout?: number): Promise<any>;
```

#### Params

| Name        | Type     | Required        | Description                                                                   |
|-------------|----------|-----------------|-------------------------------------------------------------------------------|
| `data`      | `any`    |  <div>No</div>  | Optional data to pass to the group.                                           |
| `groupName` | `string` |  <div>No</div>  | The name of the group to wait for. Defaults to the default group.             |
| `timeout`   | `number` |  <div>No</div>  | Timeout in milliseconds. If not specified, the default timeout is 30 seconds. |

#### Return value

A promise that resolves with the data from the master device when all devices are ready to continue.

#### Possible errors


- Error If the group name is not a string.
- Error If the timeout is not a number.
- Error If unable to wait for the group.
- Error If any other error occurs during waiting for the group.

#### Example

```ts
// wait for all devices in the group to be ready
await sos.sync.wait('someData', 'someRandomNameGroup').then((data) => {
    // this will be called once all devices are ready
    console.log('All devices are ready with data:', data);
});
```

<Separator />

### ~connect(options)~

:::danger Deprecated

This method was deprecated. Use `connect({ engine: 'sync-server' })` instead.

:::

```ts expandable
connect(options?: string): Promise<void>;
```

<Separator />

### ~init()~

:::danger Deprecated

This method was deprecated. use `sos.sync.joinGroup()` instead.

:::

```ts expandable
init(groupName?: string, deviceIdentification?: string): Promise<void>;
```

<Separator />

### ~setValue()~

:::danger Deprecated

This method was deprecated. use `sos.sync.broadcastValue()` instead.

:::

```ts expandable
setValue(key: string, value: any, groupName?: string): Promise<void>;
```