Room Background Media

Music or radio that the server plays under the voices in a room, so everyone hears the same thing at the same time.

Overview

  • A room can have background media: songs, albums or playlists from the server's music library, or a radio stream.
  • The server plays it and mixes it into the room's live audio, so guests and people on the web, iPhone, iPad, Mac and Windows all hear the same song at the same moment.
  • It sits well below the voices, and it gets quieter by itself while anyone is talking (about 15 dB), then comes back up when they stop.
  • It only plays while someone is listening in the room. When the room is empty it stops, and it carries on when someone comes back.
  • You can turn it down or mute it just for yourself. That does not change what anyone else hears.

Listening: your own volume and mute

Web app

  1. Join the room. When it has background media, a "Background media" section appears in the room, below the voice controls. It says what is playing, for example "Now playing: Song title by Artist".
  2. Use the "Background media volume" slider to set how loud it is for you (0 to 100 percent). Voices are not affected.
  3. Press "Mute background media" to silence it for you. It is a toggle button; press it again to hear it again. Your choice is remembered in this browser.

When the song changes, screen readers hear a short polite announcement such as "Now playing: Song title by Artist". It is not repeated for pauses or small changes.

iPhone and iPad (build 114 and later)

  1. Join the room. When it has background media, a "Background Media" section appears in the room, below Intercom and Broadcast. Its first row, "Background media", says what is playing, for example "Now playing: Song title by Artist", and whether it is playing, paused or waiting.
  2. Swipe up or down on the "Background media volume" slider to set how loud it is for you (0 to 100 percent, in steps of 5; it starts at 60 percent). Voices are not affected.
  3. Double tap "Mute background media" to silence it for you. Double tap again to hear it again.
  4. The same slider and switch are in Settings, Audio, under "Background Media". Your choice is remembered on this device.

When the song changes, VoiceOver says "Now playing" and the song, after anything it is already reading. To turn this off, go to Settings, Accessibility, Speech, and switch off "Background Media Song Changes". The music never shows up as a person in People, and it gets quieter while you whisper to someone.

Mac (build 114 and later)

  1. Join the room. When it has background media, a "Background media" panel appears in the room, below the whisper status and above the Members List. It says what is playing and whether it is playing, paused or waiting.
  2. Use the "Background media volume" slider (VoiceOver: interact, then Left or Right Arrow) and the "Mute background media" checkbox. They are also in Settings, Audio, under "Background Media".
  3. Open the Background Media window with Command-Option-B, from the Room menu ("Background Media..."), from the room's Room menu button, or with the "Background Media..." button in the panel. Press Escape to close it.

VoiceOver on the Mac announces "Now playing" and the song when it changes (it follows your Room events announcement setting). The music is not listed in the Members List.

Windows

The Windows app already plays background media, because it arrives on the same live audio as the voices. Separate background volume and mute controls are coming in its next update. Until then, the room volume controls apply to it.

Controlling background media

Server admins and the room's owner can control a room's background media. Room owners can also give other people this right in the room's Jellyfin access settings. In the web app these controls are in the "Background media" section:

Collapsing the section (web app): the "Background media" heading is a button. Press it to collapse the whole section, so only the heading is left, and press it again to expand it. Screen readers say "collapsed" or "expanded". Everyone can do this, and the web app remembers your choice; when your account's settings sync between devices, your other devices follow it too. The music keeps playing while the section is collapsed, and song changes are still announced.

  • Previous, Play or Pause, Next, Stop buttons. Previous goes back to the start of the song if it has played for more than 5 seconds, otherwise to the song before.
  • Background media settings (a section you expand): Shuffle, Repeat (Off, Whole queue, Current song), Crossfade, Level for everyone (Very quiet to Very loud; normal is 18 dB below voices), and "Let signed-in listeners request songs".
  • Crossfade: Off (the default), or 2 to 12 seconds. The server fades the end of each track out while the next one fades in, so everyone in the room hears the same smooth change. It works for songs, episodes and movies from Jellyfin whose length is known, and when a room switches between radio stations (the next station fades in over the old one). Skipping, Stop, Pause and changing the queue cancel a fade that has not started yet.
  • Media library: choose a source, then move through the list. It has the server's music libraries and, since October 2026, its TV and movie libraries too (their sound is played). Libraries, shows, seasons, albums, artists and playlists have an "Open" button; songs, episodes, movies, seasons, shows, albums and playlists have "Play now" and "Add to queue". Use the "Search media" box to find songs, albums, artists, playlists, shows, episodes or movies. "Back" goes up one level. Choose "Radio streams" as the source to play one of the server's radio streams.
    • Browse by: at the top of a music library you can list it by Folders, Artists, Albums or Songs; at the top of a TV library by Folders or Shows. Opening an artist lists their albums.
    • Shows, seasons and episodes come from Jellyfin's own show, season and episode information, so a season reads like "Season 1, 666 Park Avenue, 13 episodes" and an episode like "Season 1, Episode 1: Pilot, 666 Park Avenue, Episode, audio described". Audio-only shows appear as real episodes through Jellyfin's Show Converter plugin, and "audio described" is said for anything Jellyfin has tagged Audio Described.
    • Play order: a show plays season by season, episode by episode; an album by disc and track; and anything in numbered parts plays by the number, counted naturally, so Part 2 comes before Part 10, "Part One" counts as Part 1, and "Day 1", "Day 2 Austin" and so on stay in order. Playlists keep their own order.
    • A library with more than 500 items in one place shows the first 500 and says so; use Search or Browse by to reach the rest.
  • Radio stations that take turns (since October 2026): a room can switch between several of the server's radio streams. Choose "Radio streams" as the library source, choose "Play now" on the first station, then "Add to stations" on each other one. While a room has more than one station:
    • "Up next" under Now playing says which station comes next and when, for example "Up next at 3:30 PM: Soul Food Radio. Stations switch every 30 minutes." Everyone in the room sees it.
    • Next and Previous become Next station and Previous station and switch at once. The room hears the new station announced, for example "Now playing: Soul Food Radio"; with crossfade on, you first hear "Switching to Soul Food Radio" while the two fade into each other.
    • Switch stations every (in Background media settings): 5 minutes to 4 hours, 30 minutes by default, or "Never, only with Next and Previous". Stations take turns in the order they were added. Choosing Next station starts the time again.
    • The stations, the time and the crossfade are saved with the room, so they carry on after the server restarts. Remove a station from the queue with its Remove button.
  • Queue: hidden until you choose "Show queue" (the button also says how many items are queued); "Hide queue" puts it away again. It is a numbered list of what will play. The current item is marked "now playing", and episodes read with their show, season and episode. Each entry has a "Remove" button.
  • Clear all (in the queue, for people who control the room's media): asks "Clear all 3 items from the queue? What is playing now stops." Choose OK to empty the queue, or Cancel to keep it. The result is read out, for example "Queue cleared. 3 items removed.", and focus stays on the button. The room's settings (level, crossfade, shuffle, schedule) are kept. In a room playing category music, Clear all also turns category music off, so the queue isn't refilled straight away; turn it back on in the Jukebox screen.

On iPhone and iPad

Open "Background Media" from Room Actions, or double tap "Background Media Controls" in the room's Background Media section. Room owners can also open it without joining: Settings, My Rooms, choose the room, then "Background Media". The screen has:

  • Now Playing and Your Volume.
  • Controls: Previous, Play or Pause, Next and Stop.
  • Background Media Settings: Shuffle, Repeat (Off, Whole queue, Current song) and "Let signed-in listeners request songs".
  • Queue: numbered entries, the current one says "now playing". Each has a Remove button, also available as a VoiceOver action (swipe up or down).
  • Music Library: choose a source, then open libraries, artists, albums and playlists one level at a time; the Back button goes up a level. Type in "Search music" and press Search. Double tap a song to choose "Play now" or "Add to queue", or swipe up or down on any row for those actions. "Radio Streams" play a server stream now.

Listeners who may request songs see "Request a Song" instead of Music Library, and a "Request" action on songs.

On the Mac

The Background Media window (Command-Option-B) has the same parts as on iPhone: Now Playing, Your Volume, Controls (Command-Option-Space plays or pauses while the window is open), Background Media Settings, Queue with Remove buttons, and the Music Library. In the library, choose a source from the "Source" menu (or "Radio streams"), then use each row's "Open", "Play now", "Add to queue" or "Request" button. "Back" (Command-Left Bracket) goes up one level or clears a search.

When listener requests are on, signed-in listeners see the music library with a "Request" button on songs. Each person can have up to 5 requests waiting. Guests can listen but cannot control or request.

A room can also have a simple schedule (start and stop times, optionally only on some days). Outside those hours the media stays off.

Jukebox categories: music that matches the room

Every room can have a jukebox category, such as Lounge, Chill, Late night, Gaming, Quiet study or Talk (no music). When category music is on, the server picks the songs for you from the music library: songs that match the category's genres, tags and playlists come first, and if fewer than 20 songs match, other songs from the music libraries fill the rest. When the list runs out, the server picks a fresh one. Nothing plays until someone turns category music on for the room.

New rooms get a category from their name. For example, a room called "Music Lounge" gets Lounge, "Chill Zone" gets Chill, "Late Night" gets Late night, "Gaming Voice" gets Gaming, "Study Hall" gets Quiet study, and podcast, meeting, class and training rooms get Talk (no music). Rooms whose name doesn't suggest anything get no category. You can change it at any time.

The Jukebox screen (web app)

In the room's "Background media" section, choose the "Jukebox settings" button. It is there for the room's owner and managers and for server admins. The screen opens with focus on its "Jukebox" heading; Escape or the Close button closes it and returns you to the button.

  • This room: "Category for this room", the "Play music from this category" check box, "Music level for everyone", and a Schedule group ("Only play during set hours", Start time, Stop time and Days; no days checked means every day). Choose "Save room settings" to apply. "Rebuild queue from category" picks a fresh list of songs straight away.
  • Choosing songs yourself: use the Music library in the Background media section. In category mode, songs you add play next, then the category music carries on. "Play now" on an album or playlist replaces the category music until you turn it back on in the Jukebox screen.
  • Categories (server admins only): a list of every category with what it plays and which rooms use it, each with "Edit" and "Delete" buttons, and a "Create category" button. The editor has Name, Description, a "No music" check box, the music server, and check box groups for Genres, Tags, Libraries and Playlists read from the music server. No libraries checked means all music libraries (never audiobooks). Deleting a category asks you to confirm; rooms that used it are left with no category, and category music in them stops.

When a category is edited, or a room's category changes while its music is playing, the new choice takes over at the next song.

Limits

  • To keep the server fast, only a few rooms can play background media at the same time (3 by default). If the limit is reached, the room shows "Waiting: server busy" and starts by itself when a slot frees up.
  • When the server is very busy, background media waits or pauses and resumes automatically.
  • If a stream or song can't be reached, the server retries with growing pauses and skips a song that keeps failing.
  • The music library needs the server's Jellyfin connection to be set up by the server owner. All of our servers share one central Jellyfin music server and account, so the same media is available everywhere - each server just picks which of its libraries to use (Admin > Jukebox > Categories, music server libraries/genres/tags/playlists checkboxes). The library key never leaves the server; links handed to the app for playback or cover art are short-lived and only work through VoiceLink.
  • A server owner can hide a whole Jellyfin library from VoiceLink, for example one that only feeds a game world. Add its id to excludedLibraryIds (or its name to excludedLibraryNames, any letter case) on that Jellyfin server's entry in data/deploy.json (jellyfin.connection.servers) and restart VoiceLink. A hidden library and everything in it, including its playlists, is never listed, opened, searched, picked by a jukebox category, queued or played, for anyone, server admins included. Tracks from it that were already queued are removed when their turn comes. Jellyfin itself is not changed.

For app developers: protocol

All paths are relative to the server base URL, including any path prefix. Send Authorization: Bearer <accessToken>. Permissions come from the signed-in session only.

Audio

Background media arrives as ordinary relayed-audio packets to every listener in the room that has the relay on:

{ userId: "media:<roomId>", userName: "Background media", roomId, media: true,
  audioData: base64 float32 little-endian, codec: "pcm-f32", sampleRate: 48000, channels: 1,
  frameSize: 960 (20 ms), timestamp: seconds (number), seq, engine: "room-media-source",
  audioMode: "music", relayTelemetry: { jitterBufferMs: 120, serverReceivedAt } }
  • About 50 packets per second. The server has already applied the room level and voice ducking.
  • Personal volume and mute: apply your own gain to packets with media: true (or drop them when muted). Do not show media: senders as people and do not announce them joining or leaving.
  • When a room uses the server mix, room payloads have backgroundStream: null; do not start your own stream player for that room.

State

Socket event room-media-state is sent to the room on every change, and to you right after joined-room. joined-room also has room.backgroundMedia (same object, or null).

{ roomId, mode: "server-mix", enabled, status: "playing"|"paused"|"stopped"|"waiting"|"busy"|"retrying"|"ended"|"scheduled"|"error"|"loading",
  statusReason, playing, sourceType: "category"|"jellyfin"|"stream"|"url"|"none", sourceTitle,
  category: { id, name, noMusic } | null (the room's jukebox category), categoryMode: true when sourceType is "category",
  nowPlaying: { index, kind, itemId, title, artist, album, durationSec, positionSec, live, requestedBy, streamTitle?, stationName? },
  nowPlayingText: "Now playing: Title by Artist", announce: true only when the song changed,
  currentIndex, queue: [...up to 50 entries...], queueStart, queueLength, shuffle, repeat: "off"|"all"|"one",
  volumeDb, duckDb, allowUserRequests, schedule, startedBy, startedAt,
  member: { userId: "media:<roomId>", userName }, audio: { codec, sampleRate, channels, frameMs } }

REST

  • GET /api/rooms/:id/background-media - {state (full queue), permissions: {canControl, canConfigure, canRequest, canBrowse, canUseCustomUrl, signedIn, isServerAdmin}}. Anyone.
  • PUT /api/rooms/:id/background-media - control permission. Body: {sourceType: "jellyfin", serverId, itemIds: [...] | playlistId}, {sourceType: "stream", streamId?} (configured streams; without streamId the room's own), {sourceType: "url", url} (server admins only), {sourceType: "none"}; plus any of title, volumeDb (-40..0), duckDb (-40..0), shuffle, repeat, allowUserRequests, enabled, autoplay, schedule: {enabled, startTime: "HH:MM", stopTime: "HH:MM", days: [0-6], timezone}.
  • POST /api/rooms/:id/background-media/play | pause | next | previous | stop - control permission.
  • POST /api/rooms/:id/background-media/queue {serverId, itemId | itemIds, playNext?} - controllers add anything; listeners (when requests are on) one song at a time, 5 waiting max.
  • DELETE /api/rooms/:id/background-media/queue/:index - control permission.
  • GET /api/rooms/:id/background-media/library - without serverId: {servers: [{id, name, available}], streams}; with serverId: libraries; with parentId and/or search: {items: [{id, type, title, artist, album, durationSec, childCount, isFolder, playable}], total}.
  • PUT /api/rooms/:id/background-media also takes {sourceType: "category", categoryId?} (without categoryId the room's own category).
  • Every response has success; errors have error text to show. 401 = sign in, 403 = no permission, 503 with code: "no_api_key" = library not set up.

Queue, crossfade and library additions (2026-10-14)

  • DELETE /api/rooms/:roomId/background-media/queue (room controllers): empties the queue and stops playback. Answer: { cleared, categoryStopped, state, permissions }. 401 signed out, 403 without control.
  • PUT /api/rooms/:roomId/background-media accepts crossfadeSec, 0 (off) to 12; the state has crossfadeSec. Server default: roomMedia.defaultCrossfadeSec in the deploy config (0).
  • Queue entries and nowPlaying may carry seriesName, seasonNumber, episodeNumber, audioDescribed and displayTitle ("Show, Season 1, Episode 3: Title"); nowPlayingText uses displayTitle.
  • GET .../background-media/library: libraries include TV and movie libraries and a views list; items add seriesName, seriesId, seasonName, seasonNumber, episodeNumber, discNumber, trackNumber, albumArtist, year and audioDescribed. New query parameters: view (folders, artists, albums, songs, shows; with a library as parentId) and parentType (for example MusicArtist, so opening an artist lists their albums). Lists come in natural play order.

Radio stations that take turns (2026-10-14)

  • PUT /api/rooms/:roomId/background-media with {sourceType: "stream", streamIds: ["chrismix-radio", "soulfood-radio"]} (configured backgroundStreams ids, in order, up to 20) sets several stations; streamId alone still sets one. rotateMinutes: 0 (only Next/Previous) to 1440; default 30 (server default roomMedia.defaultRotateMinutes).
  • POST /api/rooms/:roomId/background-media/queue with {streamId} (room controllers) adds a station to a room already playing streams; 409 if it is already there. DELETE .../queue/:index removes one.
  • POST .../next and .../previous switch station in list order, crossfading when crossfadeSec is set.
  • State adds rotateMinutes and, for stream rooms, rotation: {stations, intervalMinutes, automatic, nextAt (ISO or null), next (queue entry), switchingTo (entry while a crossfade is under way), crossfading}. With several stations, nowPlayingText ends ", on Station name" when the station sends song titles. The switch time is saved as mediaPlayback.rotateDueAt.

Jukebox categories API

Category object: {id, name, description, noMusic, sources: {serverId, genres: [], tags: [], libraryIds: [], playlistIds: []}, createdAt, updatedAt}. The room's category is room.jukeboxCategory (id or null).

  • GET /api/jukebox/categories - signed-in users. {categories: [category + rooms: [{id, name, categoryMode, playing}]], permissions: {canEditCategories}}. Private rooms are listed only for server admins.
  • POST /api/jukebox/categories (201), PUT /api/jukebox/categories/:id, DELETE /api/jukebox/categories/:id - server admins only. Body: any category fields; omitted fields keep their values on PUT. Responses include category and the new categories list; DELETE returns {deleted, roomsCleared}: rooms that used it get no category, and category-mode rooms stop (source becomes "none").
  • GET /api/jukebox/genres?serverId=&roomId= - server admins, or managers of roomId. {servers, serverId, libraries: [{id, name, collectionType, music}], genres: [], tags: [], playlists: [{id, name, childCount}]}. Genres and tags come from the music libraries.
  • GET /api/rooms/:id/jukebox - anyone. {jukebox: {roomId, categoryId, category, categoryMode, enabled, backgroundMediaEnabled, sourceType, volumeDb, schedule, queueLength}, permissions: {canConfigure, canEditCategories, signedIn}}.
  • PUT /api/rooms/:id/jukebox - room managers and server admins. Body: any of {categoryId (id or null), enabled (true = category music on, false = off), volumeDb, duckDb, schedule, allowUserRequests, rebuild}. Returns jukebox plus state and permissions as in GET background-media.
  • POST /api/rooms/:id/jukebox/rebuild - room managers and server admins. Turns category music on and picks a fresh queue now.
  • 400 when the category plays no music, 404 when the category doesn't exist, 503 when no music server is set up.