Guide contents
Worked use cases
Each case names the roles involved, how the device connects, which pairing method fits, and the things that usually go wrong. Find the one closest to your product and read it before the step-by-step chapters.
Smart speaker or amplifier
Roles: player, controller; source if it has a line input.
- Server-initiated connection; the device advertises itself and any server in the home can use it.
- Pairing: a dynamic code spoken through the speaker if it has no display, otherwise shown on the display.
- Decide whether unpaired access is on by default. For a plain speaker it usually is: the user expects to pick it in the app and hear music.
- Set the output delay for anything after the port, such as an external amplifier, and let the user adjust it.
- Start with ESPHome for ESP32 designs, sendspin-cpp for anything else.
Streamer, output only
Roles: player, plus controller when there is a remote or an app.
- A network streamer or a DIY board: no speaker of its own, feeding a DAC, an amplifier or an optical input.
- The DAC, DSP and amplifier behind the port add delay the device cannot see. Measure it once and ship it as the default output delay; expose it in settings.
- Pairing: a dynamic code shown in your app if you have one, otherwise a static code printed on the device, entered while a button press opens the pairing window. Most users will use guest mode.
- Report hardware volume knobs as read-only when they cannot be set remotely.
- Sendspin can run next to AirPlay and Cast on the same box. While another protocol is playing, leave the Sendspin group but stay available, so the user can take the device back with Sendspin at any time. Report it unavailable only if it will not yield.
Wall tablet or display
Roles: metadata, artwork, controller; color for theming; player if it has a speaker.
- Ask for artwork in exactly the pixel size you render; the server scales for you. Use a second channel for a blurred background.
- Scheduled metadata lets you show "up next" before the track changes.
- Pairing: show a dynamic code or a QR code on the display.
- A controller acts on the group the display is in. Give the user a way to switch groups.
- Start with sendspin-js for web-based panels, sendspin-cpp for embedded displays.
Dedicated controller
Roles: controller only.
- A knob, a button panel, a remote or a voice satellite that controls the room it is in without playing anything itself.
- It receives the group's state, so a ring of LEDs can show volume and play state.
- Pairing is rarely worth the friction here; unpaired access with operator approval is the usual choice.
- Play with nothing queued resumes what the group last played, so a single button is enough.
Lighting and visualizers
Roles: visualizer, color, or both.
- Visualizer frames are timestamped like audio. Run the time filter and render each frame at its time, not on arrival.
- Ask only for the data types you use, at the rate you can render. Beat events may be absent on servers without beat detection; peaks are always there.
- Colors come with contrast guarantees, so the same palette drives both the lamp and any text overlay.
Set-top box or TV
Roles: player, source, optionally an embedded server.
- As a player it joins the speakers for music. As a source it feeds TV audio into the system so the room's speakers play the film.
- Never pass the TV audio to the local speakers directly while sending it to the system: the local output would run ahead of the network. A device that is source and player plays only what the server sends back.
- When the user switches to a game console or another input, leave the Sendspin group but stay available if Sendspin may interrupt, or report the player unavailable if it must not. Either way the server parks it and never pulls it back on its own.
- An embedded server lets the box drive the room on its own, without a music server in the house. See the app case for how client and server mode coexist.
Turntable, AUX or Bluetooth bridge
Roles: source.
- The device captures, timestamps and sends audio. The server resamples and mixes.
- Report line sense when you can detect signal; the server can start the room when the needle drops and stop it when the record ends.
- Timestamp from the time filter including drift, not offset alone, or the stream wanders over an evening.
- After a network stall, drop the backlog and resume from live capture instead of bursting old audio.
- A source always requires explicit operator approval on the server, and devices with a microphone should ship with unpaired access off.
Desktop or mobile app
Roles: player and controller as a client; a full server when the app plays.
- Idle, the app is a client: it shows up as a target for Music Assistant or any other server in the home.
- When the user starts playback in the app, it becomes a server and sends to the other speakers. Say goodbye to the server you were a client of with reason
another_server, and advertise_sendspin-server._tcpas well so client-initiated devices find you. - Clients listen on 8928 and servers on 8927 by convention, so both can run on one machine.
Software player or music server
Roles: server, client, or both.
- A software music player, a Linux audio box, a home-automation hub: add the server side to send its output to Sendspin devices, add the client side to be a target for other servers, or do both.
- Reuse aiosendspin if you are in Python; it is the server inside Music Assistant.
- Your server identity key must survive backups and migrations, or every device will treat the restored server as a stranger.
- The server UX chapter covers discovery, approval and pairing.
Several servers in one home
Roles: any; this is about coexistence.
- Music Assistant, a phone app and a set-top box can all be servers at once. Server-initiated connections make this work without configuration.
- A client holds one playback connection. A server that starts playing takes it; the one that loses it gets
another_server, keeps showing the device as available, and does not reconnect in a loop. - Each server pairs separately. A client stores at least five pairing records.
- Show the hand-over as "playing from somewhere else" in your server UI.
Picking a connection mode
Use server-initiated connections unless you have a reason not to. The client advertises itself, servers find it, and the multi-server rules above are defined. Client-initiated connections exist for scripts, test tools and software that already has a server picker of its own; what happens with two servers is then up to you.
Picking a pairing method
| Your device has | Offer |
|---|---|
| A display | Dynamic pairing code, as digits and as a QR code |
| A speaker but no display | Dynamic pairing code, spoken |
| An app of its own | Dynamic pairing code shown in the app, which acts as the device's display |
| None of these | Static pairing code printed on the device, entered while a button, a pinhole or a power-cycle pattern opens the pairing window |
| A platform that already knows the device | The platform hands the device's pairing PSK to the server, the way Home Assistant does for ESPHome devices |
Offer one code-based method, not both, so the user never has to choose between them. Every client also implements the pairing PSK method for automated hand-offs between systems. A speaker with guest mode on plays for any server the operator approves, so many users will never need to pair. The client pairing chapter has the details.