Skip to content

Update Sendspin provider to version 4.0 with many improvements#3158

Merged
marcelveldt merged 13 commits intodevfrom
feat/aiosendspin-4.0
Feb 17, 2026
Merged

Update Sendspin provider to version 4.0 with many improvements#3158
marcelveldt merged 13 commits intodevfrom
feat/aiosendspin-4.0

Conversation

@maximmaxim345
Copy link
Member

@maximmaxim345 maximmaxim345 commented Feb 13, 2026

A major rewrite of the Sendspin Server with a lot of changes and improvements.

There is a large possibility that new bugs were added in this update, please test and report any issues you encounter.

There are a couple of know issues with this version, those will be addressed in future PRs:

  • The web player can not recover from a network interruption, but the server is already prepared to allow this in the future
  • The sendspin-cli sometimes doesn't show metadata, this is a bug in the cli
  • Listening to live content like Radio streams, AirPlay input, or Spotify connect might not be reliably yet. It tries to reduce the latency as far as possible which might be too close for some clients/network conditions. A custom role or a proper proposal for the Specification to solve this issue will come later.
  • If you join a client with DSP enabled to an active stream, there might be a short audio glitch after a couple of seconds.
  • A recovered client (disconnected due to a network interruption and automatically reconnected) might have a gap of silence with the duration of the disconnection

The biggest user-facing improvements are:

  • Very low latency for real-time streams like radio, AirPlay input, and Spotify Connect
  • Keep album artwork during track skipping and while paused (client implementations might need to be updated)
  • Support multiple Sendspin servers with automatic takeover (supported with the latest VPE beta)
  • Increase maximum buffer size from 5s to 30s for more stable playback
  • More stable transmission of audio data and lower latency for commands like volume (clients may need to decrease the advertised buffer_capacity)
  • Add an advanced player option to manually select the sample rate/bit depth/codec for each client

In addition to that, this also includes a lot of under the hood changes for future features and improvements:

  • Adds the groundwork for new and custom roles (like the visualizer)
  • Adds the groundwork to implement custom role versions (for a future optimized AirPlay-to-Sendspin bridge)
Example
from aiosendspin.models.types import SUPPORTED_ROLE_VERSIONS
from aiosendspin.server.roles.player.v1 import PlayerV1Role
from aiosendspin.server.roles.registry import register_role

class PlayerCustomRole(PlayerV1Role):
    @property
    def role_id(self) -> str:
        return "player@_custom_version"

# Register and negotiate the custom player role version.
register_role("player@_custom_version", lambda client: PlayerCustomRole(client=client))
SUPPORTED_ROLE_VERSIONS["player"] = "player@_custom_version"

# Clients must advertise a matching support key for custom role versions
# (applies to player/artwork/visualizer):
# {
#   "supported_roles": ["player@_custom_version"],
#   "player@_custom_version_support": { ... }
# }
  • Adds support for hooking into aiosendspin to display custom bridges as native Sendspin players while powered off (for the Chromecast and AirPlay Sendspin bridges)
Example
from aiosendspin.models.core import ClientHelloPayload
from aiosendspin.models.player import ClientHelloPlayerSupport, SupportedAudioFormat
from aiosendspin.models.types import AudioCodec, PlayerCommand, Roles
from aiosendspin.server.server import ExternalStreamStartRequest

hello = ClientHelloPayload(
    client_id="external-airplay-living-room",
    name="Living Room AirPlay",
    version=1,
    supported_roles=[Roles.PLAYER.value],
    player_support=ClientHelloPlayerSupport(
        supported_formats=[
            SupportedAudioFormat(
                codec=AudioCodec.PCM,
                channels=2,
                sample_rate=48000,
                bit_depth=16,
            )
        ],
        buffer_capacity=100_000,
        supported_commands=[PlayerCommand.VOLUME, PlayerCommand.MUTE],
    ),
)

def on_stream_start(request: ExternalStreamStartRequest) -> None:
    # Bridge should connect transport for request.client_id here.
    return

external = server.register_external_player(hello, on_stream_start=on_stream_start)
assert not external.is_connected  # exposed before transport is connected
  • Prepare for parallelized resampling/encoding for even better performance (disabled for now for stability)

For more information, read the PR in the aiosendspin repository:

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

🔒 Dependency Security Report

📦 Modified Dependencies

music_assistant/providers/sendspin/manifest.json

Added:

Removed:

Unchanged dependencies
  • av ==16.1.0

The following dependencies were added or modified:

diff --git a/requirements_all.txt b/requirements_all.txt
index 42914953..7544fe65 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -11,7 +11,7 @@ aiojellyfin==0.14.1
 aiomusiccast==0.15.0
 aiortc>=1.6.0
 aiorun==2025.1.1
-aiosendspin==3.0.0
+aiosendspin==4.0.1
 aioslimproto==3.1.5
 aiosonos==0.1.9
 aiosqlite==0.22.1

New/modified packages to review:

  • aiosendspin==4.0.1

🔍 Vulnerability Scan Results

No known vulnerabilities found
✅ No known vulnerabilities found


Automated Security Checks

  • Vulnerability Scan: Passed - No known vulnerabilities
  • Trusted Sources: All packages have verified source repositories
  • Typosquatting Check: No suspicious package names detected
  • License Compatibility: All licenses are OSI-approved and compatible
  • Supply Chain Risk: Passed - packages appear mature and maintained

Manual Review

Maintainer approval required:

  • I have reviewed the changes above and approve these dependency updates

To approve: Comment /approve-dependencies or manually add the dependencies-reviewed label.

@balloob
Copy link
Contributor

balloob commented Feb 15, 2026

The sendspin-cli sometimes doesn't show metadata, this is a bug in the cli

Fix here Sendspin/sendspin-cli#117

Alsmost works now, but cleanup and some major bug fixes are left to iron
out. (with DSP clients)
Remove defensive timeout wrappers (`_await_with_timeout`,
`_timed_lock`) in favor of plain awaits, parallelize member
transform reads with `asyncio.gather`, and add architecture
and join-catchup lifecycle documentation.
The 50ms timeout cancelled the drain but data was already in the
pipe buffer, producing misleading warnings while playback worked
fine. Backpressure is handled by `sleep_to_limit_buffer`.
Split the join-catchup history blob into 100ms slices before
calling `prepare_historical_audio`, preventing a single large
encode from blocking the event loop for ~500ms.
@maximmaxim345 maximmaxim345 added the dependencies-reviewed Indication that any added or modified/updated dependencies on a PR have been reviewed label Feb 17, 2026
@maximmaxim345 maximmaxim345 marked this pull request as ready for review February 17, 2026 09:55
Copilot AI review requested due to automatic review settings February 17, 2026 09:55
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Sendspin provider from version 3.0.0 to 4.0.1, implementing a major architectural rewrite of the playback system. The update replaces the simple TimedClientStream approach with a sophisticated SendspinPlaybackSession coordinator that supports per-member DSP pipelines, dynamic group membership changes, and late-join historical backfill.

Changes:

  • Updates aiosendspin dependency from 3.0.0 to 4.0.1
  • Removes timed_client_stream.py and replaces it with new playback.py module implementing advanced playback pipeline architecture
  • Refactors player.py to use role-based architecture for metadata, artwork, and controller functions, with dynamic audio format configuration

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
requirements_all.txt Updates aiosendspin from 3.0.0 to 4.0.1
manifest.json Updates aiosendspin requirement to 4.0.1
provider.py Adds AlreadyRegisteredError handling and fixes unload disconnection logic to check for connection availability
player.py Major refactor to role-based architecture, removes MusicAssistantMediaStream class, integrates SendspinPlaybackSession, adds dynamic audio format configuration
playback.py New 1141-line module implementing sophisticated playback session coordinator with per-member DSP pipelines, join-catchup mechanism, and history management
timed_client_stream.py Removed (331 lines) - replaced by playback.py architecture
init.py Changes import from relative to absolute path
README.md Updates file reference from timed_client_stream.py to playback.py

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@marcelveldt
Copy link
Member

@maximmaxim345 can you have a look at CoPilot's suggestions ? Some of them make good sense to fix before merging.

@marcelveldt marcelveldt marked this pull request as draft February 17, 2026 14:18
@marcelveldt
Copy link
Member

Marked as draft while you work out these final fixes - hit the "ready for review" button once you are ready

@maximmaxim345 maximmaxim345 marked this pull request as ready for review February 17, 2026 16:21
Copilot AI review requested due to automatic review settings February 17, 2026 16:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Member

@marcelveldt marcelveldt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing job again @maximmaxim345 !

@marcelveldt marcelveldt merged commit 7b82a3a into dev Feb 17, 2026
18 of 19 checks passed
@marcelveldt marcelveldt deleted the feat/aiosendspin-4.0 branch February 17, 2026 21:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies-reviewed Indication that any added or modified/updated dependencies on a PR have been reviewed new-feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants