# Media Topic

Real-time media status and playback control via WebSocket

The **media** topic is the **recommended way** to build media widgets and remote controls. It provides real-time now-playing information and allows you to control playback directly through the same WebSocket connection.

## Why WebSocket for Media?

Unlike the [REST API](/content/docs/api/media/index.html), the WebSocket media topic:
- **Sends updates** **instantly** when track, volume, or playback state changes
- **No polling required** - zero wasted requests
- **Bidirectional** - send commands and receive feedback through one connection
- **Efficient** - Cntrl only broadcasts when something actually changes

## Smart Updates

Media events only broadcast when something changes (track, play/pause, volume, mute). No constant polling - you only receive data when it matters.

## [Subscribe](/content/docs/ws/media#subscribe/index.html)

```
{ "op": "subscribe", "data": { "topics": ["media"] } }
```

## [Event: `media_update`](/content/docs/ws/media#event-media_update/index.html)

Broadcasts immediately on subscribe, then whenever media state changes.

```
{
  "type": "media_update",
  "data": {
    "status": "playing",
    "volume": 75,
    "muted": false,
    "playing": true,
    "title": "Bohemian Rhapsody",
    "artist": "Queen",
    "supports_ctrl": true
  }
}
```

### [Field Reference](/content/docs/ws/media#field-reference/index.html)

| Field          | Type   | Description                                        |
|----------------|--------|----------------------------------------------------|
| `status`       | string | "`playing`", "`paused`", or "`stopped`"       |
| `volume`       | int    | System volume (0-100)                             |
| `muted`        | bool   | Whether system audio is muted                      |
| `playing`      | bool   | True if media is actively playing                  |
| `title`        | string | Current track title                                |
| `artist`       | string | Current artist name                                |
| `supports_ctrl`| bool   | Whether playback control is supported               |

### [When Updates Are Sent](/content/docs/ws/media#when-updates-are-sent/index.html)

Updates trigger on any of these changes:

- Track changes (new song)
- Play/pause state changes
- Mute/unmute
- Volume changes

## Volume Detection

Volume changes are detected and broadcast automatically. If you change volume using your keyboard or system controls, connected clients will see the update.

## [Sending Commands](/content/docs/ws/media#sending-commands/index.html)

### [Media Control](/content/docs/ws/media#media-control/index.html)

```
{
  "op": "media",
  "data": {
    "action": "play_pause"
  }
}
```

### [Available Actions](/content/docs/ws/media#available-actions/index.html)

#### [Playback](/content/docs/ws/media#playback/index.html)

| Action       | Description                 |
|--------------|-----------------------------|
| `play`      | Start/resume playback       |
| `pause`     | Pause playback              |
| `play_pause`| Toggle play/pause           |
| `next`      | Next track                  |
| `prev`      | Previous track              |

#### [Volume](/content/docs/ws/media#volume/index.html)

| Action       | Value           | Description                   |
|--------------|-----------------|-------------------------------|
| `volume_up` | -               | Increase volume               |
| `volume_down`| -              | Decrease volume               |
| `set_volume` | `0-100`        | Set specific volume level     |
| `mute`      | -                | Mute audio                    |
| `unmute`    | -                | Unmute audio                  |
| `toggle_mute`| -               | Toggle mute state             |

### [Set Volume Example](/content/docs/ws/media#set-volume-example/index.html)

```
{
  "op": "media",
  "data": {
    "action": "set_volume",
    "value": 50
  }
}
```

## [Event: `media_feedback`](/content/docs/ws/media#event-media_feedback/index.html)

After sending a media command, you'll receive feedback:

```
{
  "type": "media_feedback",
  "data": {
    "success": true,
    "action": "play_pause",
    "message": null
  }
}
```

### [Feedback Fields](/content/docs/ws/media#feedback-fields/index.html)

| Field    | Type   | Description                              |
|----------|--------|------------------------------------------|
| `success`| bool   | Whether the command succeeded             |
| `action` | string | The action that was executed              |
| `message`| string | Error message if failed (null on success)|

### Two Messages

After a media command, you receive:
1. `media_feedback` - Immediate confirmation 
2. `media_update` - State change (if the action changed something)

## [Configuration](/content/docs/ws/media#configuration/index.html)

In `config.json`:

```
{
  "websocket": {
    "media": {
      "enabled": true,
      "interval_ms": 500
    }
  }
}
```

The `interval_ms` controls how often the media state is polled for changes (not how often updates are sent).

## [Example Use Cases](/content/docs/ws/media#example-use-cases/index.html)

### [1. Now Playing Widget](/content/docs/ws/media#1-now-playing-widget/index.html)

Display current track with play/pause control:

```
const ws = new WebSocket("ws://localhost:9990/api/ws");
let currentMedia = null;

ws.onopen = () => {
  ws.send(
    JSON.stringify({
      op: "subscribe",
      data: { topics: ["media"] },
    }),
  );
};

ws.onmessage = (event) => {
  const { type, data } = JSON.parse(event.data);

if (type === "media_update") {
    currentMedia = data;
    document.getElementById("title").textContent = data.title || "Nothing playing";
    document.getElementById("artist").textContent = data.artist || "";
    document.getElementById("playBtn").textContent = data.playing ? "⏸" : "▶";
  }
};

function togglePlayPause() {
  ws.send(
    JSON.stringify({
      op: "media",
      data: { action: "play_pause" },
    }),
  );
}
```

### [2. Volume Slider](/content/docs/ws/media#2-volume-slider/index.html)

Real-time volume control with visual feedback:

```
const volumeSlider = document.getElementById("volume");

// Update slider when volume changes externally
ws.onmessage = (event) => {
  const { type, data } = JSON.parse(event.data);
  if (type === "media_update" && data.volume !== null) {
    volumeSlider.value = data.volume;
  }
};

// Send volume changes
volumeSlider.oninput = (e) => {
  ws.send(
    JSON.stringify({
      op: "media",
      data: { action: "set_volume", value: parseInt(e.target.value) },
    }),
  );
};
```

### [3. Smart Home Integration](/content/docs/ws/media#3-smart-home-integration/index.html)

Auto-pause when leaving home:

```javascript
// Called by your smart home system
function onUserLeftHome() {
  ws.send(
    JSON.stringify({
      op: "media",
      data: { action: "pause" },
    }),
  );
}

// Auto-mute during meetings
function onMeetingStarted() {
  ws.send(
    JSON.stringify({
      op: "media",
      data: { action: "mute" },
    }),
  );
}
```

### [4. Media Remote Control](/content/docs/ws/media#4-media-remote-control/index.html)

Full remote control for your PC:

```
const controls = {
  playPause: () => sendCommand("play_pause"),
  next: () => sendCommand("next"),
  prev: () => sendCommand("prev"),
  mute: () => sendCommand("toggle_mute"),
  volUp: () => sendCommand("volume_up"),
  volDown: () => sendCommand("volume_down"),
};

function sendCommand(action) {
  ws.send(
    JSON.stringify({
      op: "media",
      data: { action },
    }),
  );
}

// Bind to UI buttons
document.getElementById("playPauseBtn").onclick = controls.playPause;
document.getElementById("nextBtn").onclick = controls.next;
// ... etc
```

### [5. Track Change Notifications](/content/docs/ws/media#5-track-change-notifications/index.html)

Get notified when a new song starts:

```
let lastTitle = null;

ws.onmessage = (event) => {
  const { type, data } = JSON.parse(event.data);

if (type === "media_update") {
    if (data.title && data.title !== lastTitle) {
      lastTitle = data.title;
      showNotification(`Now playing: ${data.title} - ${data.artist}`);
    }
  }
};
```
