-
Notifications
You must be signed in to change notification settings - Fork 2
API Reference
Chris edited this page Jan 29, 2026
·
2 revisions
Quick reference for the most important Sendspin SDK interfaces and classes.
Main protocol client for connecting to Sendspin servers.
| Property | Type | Description |
|---|---|---|
ConnectionState |
ConnectionState |
Current connection state |
ServerName |
string? |
Connected server's name |
CurrentGroup |
GroupState? |
Current playback group state |
CurrentPlayerState |
PlayerState? |
This player's volume/mute state |
ClockSyncStatus |
ClockSyncStatus |
Clock sync statistics |
// Connection
Task ConnectAsync(Uri serverUri, CancellationToken ct = default);
Task DisconnectAsync(string? reason = null);
// Commands
Task SendCommandAsync(string command, Dictionary<string, object>? parameters = null);
Task SetVolumeAsync(int volume); // 0-100| Event | Payload | When |
|---|---|---|
ConnectionStateChanged |
ConnectionState |
Connection state changes |
GroupStateChanged |
GroupState |
Playback state/metadata changes |
PlayerStateChanged |
PlayerState |
Volume/mute changes (this player) |
ClockSyncConverged |
ClockSyncStatus |
Clock sync stabilizes |
ArtworkReceived |
byte[] |
Album artwork received |
var client = new SendspinClientService(
logger,
connection,
clockSync,
capabilities,
audioPipeline); // Optional
await client.ConnectAsync(new Uri("ws://server:8927/sendspin"));
client.GroupStateChanged += (s, group) =>
Console.WriteLine($"Playing: {group.Metadata?.Title}");
await client.SendCommandAsync("play");
await client.SetVolumeAsync(75);Interface for platform-specific audio output.
| Property | Type | Description |
|---|---|---|
State |
AudioPlayerState |
Current playback state |
Volume |
float |
Output volume (0.0-1.0) |
IsMuted |
bool |
Whether output is muted |
OutputLatencyMs |
int |
Audio output buffer latency |
CalibratedStartupLatencyMs |
int |
Push-model prefill time (default: 0) |
OutputFormat |
AudioFormat? |
Current output format |
Task InitializeAsync(AudioFormat format, CancellationToken ct = default);
void SetSampleSource(IAudioSampleSource source);
void Play();
void Pause();
void Stop();
Task SwitchDeviceAsync(string? deviceId, CancellationToken ct = default);
ValueTask DisposeAsync();| Event | Payload | When |
|---|---|---|
StateChanged |
AudioPlayerState |
Playback state changes |
ErrorOccurred |
AudioPlayerError |
Error during playback |
public enum AudioPlayerState
{
Uninitialized, // Not yet initialized
Stopped, // Initialized but not playing
Playing, // Actively playing audio
Paused, // Paused
Error // Error state
}Orchestrates audio flow from network to speakers.
| Property | Type | Description |
|---|---|---|
State |
AudioPipelineState |
Current pipeline state |
IsReady |
bool |
True when ready to receive audio |
CurrentFormat |
AudioFormat? |
Input audio format |
OutputFormat |
AudioFormat? |
Output audio format |
BufferStats |
AudioBufferStats |
Buffer statistics |
DetectedOutputLatencyMs |
int |
Detected audio device latency |
Task StartAsync(AudioFormat format);
Task StopAsync();
void Clear(); // Clear buffer (track change)
void ProcessAudioChunk(AudioChunk chunk); // Called by client
void SetVolume(int volume); // 0-100
void SetMuted(bool muted);
Task SwitchDeviceAsync(string? deviceId);| Event | Payload | When |
|---|---|---|
StateChanged |
AudioPipelineState |
Pipeline state changes |
ErrorOccurred |
AudioPipelineError |
Error in pipeline |
public enum AudioPipelineState
{
Idle, // Not started
Starting, // Initializing components
Buffering, // Filling buffer before playback
Playing, // Actively playing
Stopping, // Shutting down
Error // Error state
}Timestamped audio buffer with sync error calculation.
| Property | Type | Description |
|---|---|---|
SyncErrorMicroseconds |
long |
Raw sync error (+ = behind) |
SmoothedSyncErrorMicroseconds |
long |
EMA-filtered error |
BufferedMilliseconds |
double |
Current buffer depth |
IsReadyForPlayback |
bool |
Buffer reached target |
TargetBufferMilliseconds |
double |
Target buffer before play |
OutputLatencyMicroseconds |
long |
Set from IAudioPlayer |
TargetPlaybackRate |
double |
(Deprecated) For internal correction |
// Write (from decoder)
void Write(ReadOnlySpan<float> samples, long serverTimestamp);
// Read (from audio thread)
int ReadRaw(Span<float> buffer, long currentTimeMicroseconds); // Preferred
int Read(Span<float> buffer, long currentTimeMicroseconds); // Deprecated
// Sync correction feedback
void NotifyExternalCorrection(int samplesDropped, int samplesInserted);
// Control
void Clear(); // Reset on track change
AudioBufferStats GetStats();Server-to-local time synchronization using Kalman filter.
| Property | Type | Description |
|---|---|---|
IsConverged |
bool |
5+ stable measurements |
HasMinimalSync |
bool |
2+ measurements (quick start) |
StaticDelayMs |
double |
Manual sync offset |
// Process NTP-style measurement
void ProcessMeasurement(long t1, long t2, long t3, long t4);
// Time conversion
long ServerToClientTime(long serverTimestamp);
long ClientToServerTime(long clientTimestamp);
// Status
ClockSyncStatus GetStatus();
void Reset();public record ClockSyncStatus
{
public double OffsetMicroseconds { get; init; } // Server-to-client offset
public double DriftMicrosecondsPerSecond { get; init; } // Clock drift rate
public int MeasurementCount { get; init; } // Total measurements
public bool IsConverged { get; init; }
public bool HasMinimalSync { get; init; }
}mDNS-based server discovery.
| Property | Type | Description |
|---|---|---|
Servers |
IReadOnlyCollection<DiscoveredServer> |
Found servers |
IsRunning |
bool |
Discovery active |
Task StartAsync(); // Start continuous discovery
Task StopAsync(); // Stop discovery
Task<IEnumerable<DiscoveredServer>> ScanAsync(TimeSpan timeout); // One-time scan| Event | Payload | When |
|---|---|---|
ServerFound |
DiscoveredServer |
New server found |
ServerLost |
DiscoveredServer |
Server disappeared |
ServerUpdated |
DiscoveredServer |
Server info changed |
public record DiscoveredServer(
string Id,
string Name,
Uri Uri,
string? Version);Identifies your player to servers.
public class ClientCapabilities
{
public string ClientId { get; set; } // Unique ID (auto-generated if null)
public string ClientName { get; set; } // Display name
public string? ProductName { get; set; } // Product model
public string? Manufacturer { get; set; } // Brand/company
public string? SoftwareVersion { get; set; } // App version
public List<string> Roles { get; set; } // Feature support
public List<AudioFormat> AudioFormats { get; set; } // Supported codecs
public int BufferCapacity { get; set; } // Max buffer (bytes)
public List<string> ArtworkFormats { get; set; } // jpeg, png
public int ArtworkMaxSize { get; set; } // Max artwork px
public int InitialVolume { get; set; } // 0-100
public bool InitialMuted { get; set; }
}Calculates sync correction strategy based on error.
| Property | Type | Description |
|---|---|---|
CurrentMode |
SyncCorrectionMode |
Current correction mode |
TargetPlaybackRate |
double |
Playback rate (1.0 = normal) |
DropEveryNFrames |
int |
Drop interval (0 = disabled) |
InsertEveryNFrames |
int |
Insert interval (0 = disabled) |
void UpdateFromSyncError(long rawError, long smoothedError);
void Reset();| Event | Payload | When |
|---|---|---|
CorrectionChanged |
ISyncCorrectionProvider |
Correction strategy changes |
public enum SyncCorrectionMode
{
None, // Within deadband
Resampling, // Rate adjustment (1-15ms)
Dropping, // Drop frames (>15ms behind)
Inserting // Insert frames (>15ms ahead)
}Configuration for sync correction behavior.
public class SyncCorrectionOptions
{
public double MaxSpeedCorrection { get; set; } // Default: 0.02 (2%)
public double CorrectionTargetSeconds { get; set; } // Default: 3.0
public long ResamplingThresholdMicroseconds { get; set; } // Default: 15,000 (15ms)
public long ReanchorThresholdMicroseconds { get; set; } // Default: 500,000 (500ms)
public long StartupGracePeriodMicroseconds { get; set; } // Default: 500,000
// Presets
public static SyncCorrectionOptions Default { get; } // Conservative (Windows)
public static SyncCorrectionOptions CliDefaults { get; } // Aggressive (CLI)
}Describes audio codec and format.
public class AudioFormat
{
public string Codec { get; set; } // "opus", "flac", "pcm"
public int SampleRate { get; set; } // 48000, 44100, etc.
public int Channels { get; set; } // 1, 2
public int? BitDepth { get; set; } // 16, 24, 32 (PCM)
public int? Bitrate { get; set; } // kbps (lossy)
public string? CodecHeader { get; set; } // Base64 codec data
}Playback group state and metadata.
public class GroupState
{
public string GroupId { get; set; }
public string? Name { get; set; }
public PlaybackState PlaybackState { get; set; } // Playing, Paused, Stopped
public int Volume { get; set; } // Group average (0-100)
public bool Muted { get; set; }
public TrackMetadata? Metadata { get; set; }
public bool Shuffle { get; set; }
public string? Repeat { get; set; } // "off", "one", "all"
}Current track information.
public class TrackMetadata
{
public string? Title { get; set; }
public string? Artist { get; set; }
public string? AlbumArtist { get; set; }
public string? Album { get; set; }
public string? ArtworkUrl { get; set; }
public int? Year { get; set; }
public int? Track { get; set; }
public PlaybackProgress? Progress { get; set; }
public double? Duration { get; set; } // Computed
public double? Position { get; set; } // Computed
}- Getting Started - First connection
- Building a Minimal Player - Complete example
- Architecture - How components work together
- NuGet Package - Package page
- Source Code - Full SDK source