Skip to content

Getting Started

Chris edited this page Jan 29, 2026 · 2 revisions

Getting Started

This guide will get you connected to a Sendspin server in about 5 minutes. We'll start with a simple console app that discovers servers and logs track changes - no audio playback yet.

Step 1: Create a New Project

dotnet new console -n MyFirstPlayer
cd MyFirstPlayer

Step 2: Add the SDK

dotnet add package Sendspin.SDK
dotnet add package Microsoft.Extensions.Logging.Console

Step 3: Write the Code

Replace Program.cs with:

using Microsoft.Extensions.Logging;
using Sendspin.SDK.Client;
using Sendspin.SDK.Connection;
using Sendspin.SDK.Discovery;
using Sendspin.SDK.Synchronization;

// Set up logging
using var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddConsole();
    builder.SetMinimumLevel(LogLevel.Information);
});

var logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Starting Sendspin player...");

// Step 1: Discover servers via mDNS
var discovery = new MdnsServerDiscovery(loggerFactory.CreateLogger<MdnsServerDiscovery>());

discovery.ServerFound += (sender, server) =>
    logger.LogInformation("Found server: {Name} at {Uri}", server.Name, server.GetWebSocketUri());

discovery.ServerLost += (sender, server) =>
    logger.LogInformation("Lost server: {Name}", server.Name);

await discovery.StartAsync();
logger.LogInformation("Scanning for servers (5 seconds)...");
await Task.Delay(5000);

var servers = discovery.Servers.ToList();
if (servers.Count == 0)
{
    logger.LogError("No Sendspin servers found. Is Music Assistant running?");
    return;
}

// Step 2: Connect to the first server
var serverUri = servers.First().GetWebSocketUri();
logger.LogInformation("Connecting to {Uri}...", serverUri);

var connection = new SendspinConnection(loggerFactory.CreateLogger<SendspinConnection>());
var clockSync = new KalmanClockSynchronizer(loggerFactory.CreateLogger<KalmanClockSynchronizer>());

var capabilities = new ClientCapabilities
{
    ClientName = "My First Player",
    ProductName = "Tutorial Player",
    Manufacturer = "Me",
    SoftwareVersion = "1.0.0"
};

var client = new SendspinClientService(
    loggerFactory.CreateLogger<SendspinClientService>(),
    connection,
    clockSync,
    capabilities
);

// Step 3: Handle events
client.ConnectionStateChanged += (sender, state) =>
    logger.LogInformation("Connection state: {State}", state);

client.GroupStateChanged += (sender, group) =>
{
    var meta = group.Metadata;
    if (meta != null)
    {
        logger.LogInformation("Now playing: {Title} by {Artist}",
            meta.Title ?? "Unknown",
            meta.Artist ?? "Unknown");
    }
    logger.LogInformation("Playback state: {State}, Volume: {Volume}",
        group.PlaybackState, group.Volume);
};

client.ClockSyncConverged += (sender, status) =>
    logger.LogInformation("Clock sync converged! Offset: {Offset:F2}ms",
        status.OffsetMicroseconds / 1000.0);

// Step 4: Connect!
await client.ConnectAsync(serverUri);
logger.LogInformation("Connected to {ServerName}!", client.ServerName);

// Keep running
logger.LogInformation("Press Enter to disconnect...");
Console.ReadLine();

await client.DisconnectAsync();
await discovery.StopAsync();
logger.LogInformation("Disconnected. Goodbye!");

Step 4: Run It

dotnet run

Expected Output

info: Program[0]
      Starting Sendspin player...
info: Program[0]
      Scanning for servers (5 seconds)...
info: Program[0]
      Found server: Music Assistant at ws://192.168.1.100:8927/sendspin
info: Program[0]
      Connecting to ws://192.168.1.100:8927/sendspin...
info: Program[0]
      Connection state: Connected
info: Program[0]
      Clock sync converged! Offset: 1234567.89ms
info: Program[0]
      Connected to Music Assistant!
info: Program[0]
      Now playing: Bohemian Rhapsody by Queen
info: Program[0]
      Playback state: Playing, Volume: 75

Note: The large clock offset (millions of ms) is normal - the server uses monotonic time starting near 0, while we use Unix epoch time. The Kalman filter handles this difference.

What Just Happened?

  1. mDNS Discovery - MdnsServerDiscovery scanned the network for _sendspin-server._tcp services
  2. WebSocket Connection - SendspinConnection established a WebSocket to the server
  3. Handshake - SendspinClientService sent client/hello with our capabilities
  4. Clock Sync - KalmanClockSynchronizer exchanged timing messages to synchronize clocks
  5. Group State - Server sent group/update with current playback state and metadata

Troubleshooting

"No Sendspin servers found"

  1. Check your server - Is Music Assistant running with Sendspin enabled?
  2. Same network - Are you on the same subnet as the server?
  3. Firewall - mDNS uses UDP port 5353. Ensure it's not blocked.
  4. Try manual connection - Skip discovery and connect directly:
// Instead of discovery, connect directly:
var serverUri = new Uri("ws://192.168.1.100:8927/sendspin");
await client.ConnectAsync(serverUri);

"Connection refused" or timeout

  1. Check the URL - Default port is 8927, path is /sendspin
  2. Firewall - Ensure TCP port 8927 is open
  3. Server logs - Check Music Assistant logs for errors

Clock sync never converges

  • This usually indicates network issues (high latency/packet loss)
  • The SDK will still work, but sync accuracy may be reduced
  • Check for network congestion or Wi-Fi interference

Next Steps

You've successfully connected to a Sendspin server! But there's no audio yet. In the next section, we'll implement IAudioPlayer and wire up the full audio pipeline.


Next: Building a Minimal Player - Add audio playback with sync correction

Clone this wiki locally