Python library wrapping aiosendspin and sounddevice for programmatic audio playback
Project description
aiosendspin-sounddevice
⚠️ Work in Progress
This library is currently under active development and not yet available on PyPI. API might change heavily. It's also not versioned yet.
Python library for programmatic audio playback from Sendspin servers. Provides a clean API for connecting to Sendspin servers, receiving synchronized audio streams, and playing them through local audio devices with precise time synchronization, buffering, and drift correction.
Installation
Note: This package is not yet available on PyPI. Install from source:
git clone <repository-url>
cd aiosendspin-sounddevice
pip install .
For development with documentation support:
pip install -e ".[dev]"
Documentation
API documentation is available in the docs/ directory. To build the documentation:
cd docs
make html
The generated HTML documentation will be in docs/build/html/. See docs/README.md for more details.
Quick Start
import asyncio
from aiosendspin_sounddevice import SendspinAudioClient, SendspinAudioClientConfig
async def main():
config = SendspinAudioClientConfig(
url="ws://192.168.1.100:8080/sendspin",
client_id="my-client",
client_name="My Player",
)
client = SendspinAudioClient(config)
try:
await client.connect()
print("Connected! Playing audio... Press Ctrl+C to stop")
await client.wait_for_disconnect()
except KeyboardInterrupt:
print("\nStopping...")
finally:
await client.disconnect()
if __name__ == "__main__":
asyncio.run(main())
See examples/simple.py for a minimal working example, examples/comprehensive.py for all features, examples/discovery.py for server discovery, examples/controller.py for controller commands, or examples/tui.py for a full terminal UI example.
Architecture
Component Diagram
graph TB
SAC[SendspinAudioClient<br/>Main API - Connection, State Management, Event Handling, Controller Commands]
ASH[AudioStreamHandler<br/>Stream Lifecycle Management]
AP[AudioPlayer<br/>Audio Playback with Time Sync]
AS[AppState<br/>State Store]
ADM[AudioDeviceManager<br/>Device Discovery]
SD[ServiceDiscovery<br/>Server Discovery via mDNS]
SC[SendspinClient<br/>aiosendspin]
SAC -->|creates/manages| ASH
SAC -->|creates/manages| AS
SAC -->|uses| ADM
SAC -->|uses| SD
SAC -->|wraps| SC
ASH -->|creates/manages| AP
SAC -->|reads/updates| AS
SAC -->|sends commands| SC
ASH -->|uses| SC
AP -->|uses| SC
style SAC fill:#e1f5ff
style ASH fill:#fff4e1
style AP fill:#ffe1f5
style AS fill:#e1ffe1
style ADM fill:#f5e1ff
style SD fill:#e1f5e1
style SC fill:#ffe1e1
Component Responsibilities
SendspinAudioClient
- Purpose: Main public API for library users
- Responsibilities:
- Connection management (connect, disconnect)
- Configuration and initialization
- Event listener setup and delegation
- State query methods (get_metadata, get_playback_state, get_supported_commands, etc.)
- Controller commands (play, pause, next_track, previous_track, switch_group, toggle_play_pause)
- Volume control (set_volume)
- Timing metrics access
- Interactions:
- Creates and manages
AudioStreamHandler - Creates and manages
AppState - Uses
AudioDeviceManager(viaresolve_audio_device()) - Wraps
SendspinClientfrom aiosendspin - Updates
AppStatebased on server events - Delegates audio chunks to
AudioStreamHandler - Sends media commands to server via
SendspinClient
- Creates and manages
AudioStreamHandler
- Purpose: Manages audio stream lifecycle and format changes
- Responsibilities:
- Handles stream start/end/clear events
- Routes audio chunks to
AudioPlayer - Manages
AudioPlayerinitialization and reconfiguration - Clears audio queue on stream events
- Interactions:
- Creates and manages
AudioPlayerinstances - Receives audio chunks from
SendspinAudioClient - Receives stream events from
SendspinAudioClient - Calls
AudioPlayer.submit()for audio chunks - Calls
AudioPlayer.clear()on stream events
- Creates and manages
AudioPlayer
- Purpose: Low-level time-synchronized audio playback
- Responsibilities:
- Accepts audio chunks with server timestamps
- Time synchronization and drift correction
- Buffering and underrun prevention
- Playback speed adjustment for sync correction
- Gap/overlap detection and handling
- Volume and mute control
- Interactions:
- Receives audio chunks from
AudioStreamHandler - Uses
SendspinClient.compute_play_time()andcompute_server_time()for time sync - Outputs audio via
sounddevice - Provides timing metrics to
SendspinAudioClient
- Receives audio chunks from
AppState
- Purpose: Mirrors server state for client presentation
- Responsibilities:
- Stores playback state, metadata, volume, group info
- Tracks progress with interpolation support
- Provides
update_metadata()anddescribe()methods
- Interactions:
- Updated by
SendspinAudioClientevent handlers - Read by
SendspinAudioClientquery methods - Used for progress interpolation calculations
- Updated by
AudioDeviceManager
- Purpose: Audio device discovery and selection
- Responsibilities:
- Discovers available audio output devices
- Provides device lookup methods (by index, name)
- Caches device list
- Interactions:
- Used by
SendspinAudioClientviaresolve_audio_device()helper - Provides
AudioDeviceinstances for device selection - Static method
list_audio_devices()for public API
- Used by
ServiceDiscovery
- Purpose: mDNS-based server discovery
- Responsibilities:
- Discovers Sendspin servers on the local network via mDNS
- Tracks multiple discovered servers
- Provides continuous discovery or one-time discovery
- Interactions:
- Used independently or with
SendspinAudioClient - Provides
DiscoveredServerinstances with server information - Class method
discover_servers()for one-time discovery
- Used independently or with
Data Flow
Connection Flow
User → SendspinAudioClient.connect()
↓
SendspinClient.connect() (aiosendspin)
↓
Setup listeners → Event handlers update AppState
↓
AudioStreamHandler ready to receive chunks
Audio Playback Flow
Server → SendspinClient → SendspinAudioClient._handle_audio_chunk()
↓
AudioStreamHandler.on_audio_chunk()
↓
AudioPlayer.submit()
↓
sounddevice (audio output)
State Update Flow
Server → SendspinClient → SendspinAudioClient event handlers
↓
AppState.update_*()
↓
Optional user callbacks
↓
User query methods (get_metadata, etc.)
Event Handler Flow
Server Event → SendspinClient listener
↓
SendspinAudioClient._handle_*()
↓
AppState.update()
↓
Optional user callback (on_metadata_update, etc.)
↓
_print_event() (logs + on_event callback)
Controller Command Flow
User → SendspinAudioClient.play() / pause() / next_track() / etc.
↓
send_media_command() validates against supported_commands
↓
SendspinClient.send_group_command()
↓
Server processes command
↓
Server sends state update → Event Handler Flow
Server Discovery Flow
User → ServiceDiscovery.start() or ServiceDiscovery.discover_servers()
↓
mDNS service browser listens for _sendspin-server._tcp.local.
↓
Servers discovered → DiscoveredServer instances
↓
User selects server → SendspinAudioClient.connect(url)
Key Design Patterns
- Delegation:
SendspinAudioClientdelegates audio handling toAudioStreamHandler, which delegates playback toAudioPlayer - State Management:
AppStatecentralizes all state, updated by event handlers, read by query methods - Event-Driven: Server events trigger handlers that update state and call user callbacks
- Reference Design: All core audio playback and synchronization logic is based on the original sendspin-cli implementation.
External Dependencies
- aiosendspin.SendspinClient: WebSocket connection and protocol handling
- sounddevice: Audio output device access and playback
- numpy: Audio data processing
- zeroconf: mDNS service discovery for server discovery
Features
- ✅ Audio Playback: Time-synchronized audio playback with DAC-level precision
- ✅ Server Discovery: mDNS-based discovery of Sendspin servers on the network
- ✅ Controller Commands: Full support for media control (play, pause, next, previous, switch group)
- ✅ State Management: Real-time state tracking with metadata, progress, and volume
- ✅ Event Listeners: Optional callbacks for reactive programming
- ✅ Audio Device Management: Object-oriented audio device discovery and selection
- ✅ Progress Interpolation: Client-side progress calculation for smooth UI updates
Limitations
See FEATURE_COMPARISON.md for detailed comparison with sendspin-cli.
The library focuses on the player and controller roles. Server functionality and advanced features are not included.
License
Apache-2.0
Credits
Based on the sendspin-cli by the Sendspin Protocol authors.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aiosendspin_sounddevice-0.1.0.tar.gz.
File metadata
- Download URL: aiosendspin_sounddevice-0.1.0.tar.gz
- Upload date:
- Size: 35.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a7bc4e6c9740d7bc4184ba0ce9e5be477902aa0ffb1d5a157e3a41206c42051f
|
|
| MD5 |
9e4d34ad752eb067bd12d02e3a336305
|
|
| BLAKE2b-256 |
f55c45de8f05c54831371656409321bd8ef4a069293157763a389d8bc3f8051f
|
File details
Details for the file aiosendspin_sounddevice-0.1.0-py3-none-any.whl.
File metadata
- Download URL: aiosendspin_sounddevice-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2b193ee21723d403d8fc3a19bf6b146563a21bfed86f9a67df0e2844796fe95
|
|
| MD5 |
81bca4a29e574a5859e11dffb27cd02c
|
|
| BLAKE2b-256 |
c4772ed9e18851a08f08e2b5319c954e1bd2f0baa4cd9c31cacbb0c3193cdee9
|