# SocketSvcClientApi

Cross-mod client-side contract: query voice state (mute/talking/connection) and render sounds that only the local player hears, positioned in 3D like a normal in-game sound.

Source: https://socketsvc.vercel.app/api/client/SocketSvcClientApi
<Callout title="Generated from source">
  Interface `com.socketsvc.client.api.SocketSvcClientApi` — generated from [SocketSvcClientApi.java](https://github.com/HippoDev03/SocketSVC/blob/main/client/common/src/main/java/com/socketsvc/client/api/SocketSvcClientApi.java). Edit the Javadoc in the Java source, then run `pnpm gen:api`.
</Callout>

```java
package com.socketsvc.client.api;

public interface SocketSvcClientApi { ... }
```

Cross-mod client-side contract: query voice state (mute/talking/connection) and render
sounds that only the local player hears, positioned in 3D like a normal in-game sound. This is
**not** a way to broadcast audio as your own microphone to other players - channels created
here are local-only and never touch the voice connection.

Look it up with `#get()` on any loader (Fabric additionally publishes it in the object
share under `#OBJECT_SHARE_KEY`). Mod init order isn't guaranteed, so look this up lazily
(e.g. the first time you need it) rather than caching the result at startup.

## Constants

| Constant | Description |
| --- | --- |
| `String OBJECT_SHARE_KEY =` | — |
| `int API_VERSION = 1` | — |

## Methods

### get

```java
static SocketSvcClientApi get()
```

The registered implementation, or null until one registers itself.

### register

```java
static void register(SocketSvcClientApi api)
```

Called by the implementation once it is ready.

### isVoiceConnected

```java
boolean isVoiceConnected()
```

Whether the local player is currently connected to a SocketSVC voice server.

### isMuted

```java
boolean isMuted()
```

Whether the local player's own microphone is muted (including as a side effect of being deafened).

### isDeafened

```java
boolean isDeafened()
```

Whether the local player is deafened (not hearing incoming voice).

### isPushToTalkKeyHeld

```java
boolean isPushToTalkKeyHeld()
```

Whether the local player is currently holding down the push-to-talk key, regardless of the
configured activation type.

### isPlayerConnected

```java
boolean isPlayerConnected(UUID player)
```

Whether `player` is connected to the same voice server as the local player.

### isPlayerSpeaking

```java
boolean isPlayerSpeaking(UUID player)
```

Whether `player` is audibly speaking right now (i.e. voice frames from them are
currently being played back).

### createEntityChannel

```java
LocalEntityAudioChannel createEntityChannel(UUID id, Entity entity)
```

Creates a local-only channel that follows `entity` around, fading out past its range.

| Parameter | Description |
| --- | --- |
| `id` | a caller-chosen ID for this channel, e.g. to look it up or avoid duplicates. |

### createPositionalChannel

```java
LocalPositionalAudioChannel createPositionalChannel(UUID id, SpatialPosition position, float range)
```

Creates a local-only channel fixed (or later moved via `setPosition`) at a point in the world.

### createStaticChannel

```java
LocalStaticAudioChannel createStaticChannel(UUID id)
```

Creates a local-only channel with no spatialization, e.g. a UI sound effect.

### screens

```java
default java.util.List<VoiceScreen> screens()
```

The screens this server has published, or empty when it has none or has not said.

SocketSVC resolves what the server sent and keeps the timecode in step; it draws nothing
and decodes nothing. Turning one of these into a picture is what the cinema addon is for.

**Returns:** a snapshot, safe to hold; the playheads it carries are as of `#screenSnapshotAgeSeconds()` ago

### screenSnapshotAgeSeconds

```java
default double screenSnapshotAgeSeconds()
```

How long ago the current snapshot arrived, in seconds.

The playhead travels as a position and the moment it was true, not as a running clock -
so where a film is _now_ is [`positionAt(double)`](/api/client/VoiceScreen) of this. The server
re-sends a fresh snapshot every few seconds, which is what stops two clocks walking apart.

### ffmpegBinary

```java
default java.nio.file.Path ffmpegBinary()
```

The FFmpeg binary SocketSVC has available, or `null` when it is not installed.

SocketSVC downloads this on demand for the soundboard, so an addon that needs to decode
media can use the one that is already there instead of shipping or fetching its own. Null is
an ordinary answer, not an error: a player may simply have declined the download.

### ytDlpBinary

```java
default java.nio.file.Path ytDlpBinary()
```

The yt-dlp binary SocketSVC has available, or `null` when it is not installed.

The companion to `#ffmpegBinary()`, and the piece that turns a page somebody pasted
into something a decoder can open: FFmpeg cannot play a YouTube or Twitch _watch_ URL,
because that address serves an HTML page rather than a media stream. Resolving it happens on
each client, which is the same rule the rest of the media path follows - nothing a server
sends is ever fetched by the server.

Null is an ordinary answer: yt-dlp is downloaded on demand and a player may have declined
it. An addon that needs it should say so rather than failing silently.

### ffmpeg

```java
default Tool ffmpeg()
```

FFmpeg's state. A host that only lends a path answers from it.

### ytDlp

```java
default Tool ytDlp()
```

yt-dlp's state, the same way.

### requestDecoders

```java
default void requestDecoders(boolean withYtDlp)
```

Asks the host to fetch the decoding tools that are missing, in the background.

For an addon that has something to play and nothing to play it with. The host downloads
what is absent - FFmpeg, and yt-dlp when asked for - into its own cache, tells the player
once in chat what it is doing and why, and the addon watches `#ffmpeg()` and
`#ytDlp()` until they are `ToolStatus#READY`. Nothing here blocks, and asking
while a download is running is ignored rather than started twice.

Without this the only way a player ever got yt-dlp was by pasting a URL into the
soundboard, which is not something anybody standing in front of a blank screen would think
to do.

| Parameter | Description |
| --- | --- |
| `withYtDlp` | whether yt-dlp is wanted as well as FFmpeg - a source that is a web page rather than a media file needs it, a direct file does not |

### outputLatencySeconds

```java
default double outputLatencySeconds()
```

How much sound the output device is still holding, in seconds, past what the local channels
report as queued.

A frame handed to a channel is mixed and then written to the sound card's own buffer, and
sits there for a while before anybody hears it. An addon keeping sound in step with a
picture has to subtract this, or it judges the sound to be further along than it is and
holds the picture back to match - which is heard as the sound running late by exactly this
much, all the time.

Measured from the device rather than guessed, and zero when nothing is playing.

## Nested types

- `final class Registry`
- `enum ToolStatus`
- `record Tool(ToolStatus status, double progress, String failure)`