NET Network Synchronization
Synchronize audio playback across multiple devices on your local network with sample-accurate precision. Perfect for multi-room audio, live performances, DJ setups, and synchronized installations.
✨ New in v2.5.2
Network synchronization enables multiple devices to play audio in perfect sync across your local network
with <5ms accuracy on LAN and <20ms on WiFi. Zero-configuration, offline operation, and graceful
degradation included.
Overview
NetworkSync provides a complete solution for multi-device audio synchronization:
- Server/Client Architecture - One device acts as timing master, others follow
- Sample-Accurate Sync - Sub-20ms synchronization across all devices
- Full Transport Control - Play, Pause, Stop, Seek, Tempo synchronized
- Automatic Discovery - Clients find servers automatically on local network
- Graceful Degradation - Automatic fallback to standalone mode if connection lost
- Zero-GC Performance - No impact on audio quality (<3% CPU overhead)
Key Features
| Feature | Description |
|---|---|
| Local Network Only | Works entirely offline, no internet required |
| Auto-Discovery | Clients automatically find servers on LAN |
| Latency Compensation | Automatic network delay measurement and compensation |
| Connection Resilience | Auto-reconnect with exponential backoff |
| Offline Playback | Clients continue playing if server disconnects |
| Zero-GC | No heap allocations in hot path |
| Low Bandwidth | <15 KB/s per client |
| Thread Isolation | Network never blocks audio threads |
Synchronization Accuracy
| Network Type | Typical Accuracy | Maximum Drift |
|---|---|---|
| Gigabit LAN | <2ms | <5ms |
| 100Mbps LAN | <5ms | <10ms |
| WiFi 5/6 (5GHz) | <10ms | <20ms |
| WiFi 4 (2.4GHz) | <20ms | <50ms |
Quick Start
Server Setup (Control Device)
Server Mode - Basic Setup
using OwnaudioNET;
// Initialize audio system
await OwnaudioNet.InitializeAsync();
OwnaudioNet.Start();
// Start as network sync server
await OwnaudioNet.StartNetworkSyncServerAsync(
port: 9876,
useLocalTimeOnly: true); // No internet required!
// Get mixer and add tracks
var mixer = OwnaudioNet.GetAudioMixer();
var track = new FileSource("song.mp3");
track.AttachToClock(mixer.MasterClock);
mixer.AddSource(track);
// All commands are automatically broadcast to clients
track.Play(); // All clients start playing
track.Pause(); // All clients pause
track.Seek(30); // All clients seek to 30 seconds
// Monitor connected clients
var status = OwnaudioNet.GetNetworkSyncStatus();
Console.WriteLine($"Connected clients: {status.ClientCount}");
Client Setup (Follower Devices)
Client Mode - Basic Setup
using OwnaudioNET;
// Initialize audio system
await OwnaudioNet.InitializeAsync();
OwnaudioNet.Start();
// Connect to server (auto-discovery or manual IP)
await OwnaudioNet.StartNetworkSyncClientAsync(
serverAddress: "192.168.1.100", // Or null for auto-discovery
port: 9876,
allowOfflinePlayback: true); // Continue if disconnected
// Add SAME tracks as server
var mixer = OwnaudioNet.GetAudioMixer();
var track = new FileSource("song.mp3"); // Same file as server!
track.AttachToClock(mixer.MasterClock);
mixer.AddSource(track);
// Client automatically follows server commands
// No manual control needed!
// Monitor connection state
OwnaudioNet.NetworkSyncConnectionChanged += (sender, e) =>
{
Console.WriteLine($"Connection: {e.NewState}");
if (e.NewState == ConnectionState.Synced)
Console.WriteLine("✅ Synchronized with server!");
else if (e.NewState == ConnectionState.Disconnected)
Console.WriteLine("⚠️ Disconnected - playing standalone");
};
Server Mode
Starting a Server
Server Configuration
// Start server with custom port
await OwnaudioNet.StartNetworkSyncServerAsync(
port: 9876, // UDP port (default: 9876)
useLocalTimeOnly: true); // Use local time sync only
// Server is now broadcasting at 100Hz (10ms interval)
Broadcasting Commands
Transport Control
// All FileSource commands are automatically broadcast
var track = new FileSource("music.mp3");
track.AttachToClock(mixer.MasterClock);
mixer.AddSource(track);
// These commands are broadcast to all clients:
track.Play(); // Start playback
track.Pause(); // Pause playback
track.Stop(); // Stop playback
track.Seek(45.0); // Seek to 45 seconds
track.Tempo = 1.2f; // Set tempo to 120%
// Manual command broadcasting (advanced)
var cmd = NetworkSyncProtocol.CreatePlayCommand(
ntpTimestamp: DateTime.UtcNow.Ticks,
scheduledExecutionTime: DateTime.UtcNow.AddMilliseconds(100).Ticks,
startPosition: 0.0);
OwnaudioNet.BroadcastCommand(ref cmd);
Monitoring Clients
Client Monitoring
// Get server status
var status = OwnaudioNet.GetNetworkSyncStatus();
if (status.IsServer)
{
Console.WriteLine($"Server running");
Console.WriteLine($"Connected clients: {status.ClientCount}");
Console.WriteLine($"Time sync tier: {status.TimeSyncTier}");
}
// Client connection events
// (Events are raised on the server when clients connect/disconnect)
// Note: Currently implemented in NetworkSyncServer class
Client Mode
Connecting to Server
Client Connection Options
// Option 1: Auto-discovery (recommended)
await OwnaudioNet.StartNetworkSyncClientAsync(
serverAddress: null, // Auto-discover server
port: 9876,
allowOfflinePlayback: true);
// Option 2: Manual IP address
await OwnaudioNet.StartNetworkSyncClientAsync(
serverAddress: "192.168.1.100", // Specific server IP
port: 9876,
allowOfflinePlayback: true);
// Option 3: Hostname
await OwnaudioNet.StartNetworkSyncClientAsync(
serverAddress: "audio-server.local",
port: 9876,
allowOfflinePlayback: true);
Connection States
| State | Description | Local Control |
|---|---|---|
Disconnected |
Not connected to server | ✅ Allowed |
Connecting |
Attempting to connect | ❌ Blocked |
Connected |
Connected but not synced | ❌ Blocked |
Synced |
Fully synchronized | ❌ Blocked |
Handling Connection Loss
Connection Resilience
// Monitor connection state changes
OwnaudioNet.NetworkSyncConnectionChanged += (sender, e) =>
{
switch (e.NewState)
{
case ConnectionState.Disconnected:
Console.WriteLine("⚠️ Disconnected from server");
Console.WriteLine(" Continuing playback in standalone mode");
// Client automatically continues playing
break;
case ConnectionState.Connecting:
Console.WriteLine("🔄 Reconnecting to server...");
break;
case ConnectionState.Connected:
Console.WriteLine("✅ Connected to server");
break;
case ConnectionState.Synced:
Console.WriteLine("🎵 Synchronized with server!");
var status = OwnaudioNet.GetNetworkSyncStatus();
Console.WriteLine($" Latency: {status.AverageLatency:F2}ms");
break;
}
};
// Check if local control is allowed
if (OwnaudioNet.IsNetworkSyncLocalControlAllowed())
{
// Can control playback locally (disconnected)
track.Play();
track.Seek(60);
}
else
{
// Server is controlling playback
Console.WriteLine("Server is in control");
}
Automatic Reconnection
Clients automatically attempt to reconnect if the server becomes unavailable.
After 30 seconds of no server response, the client switches to standalone mode
and continues playback. When the server comes back online, the client automatically
reconnects and resynchronizes.
API Reference
OwnaudioNet Methods
| Method | Description |
|---|---|
StartNetworkSyncServerAsync(port, useLocalTimeOnly) |
Start as network sync server |
StartNetworkSyncClientAsync(serverAddress, port, allowOfflinePlayback) |
Start as network sync client |
StopNetworkSync() |
Stop network synchronization |
GetNetworkSyncStatus() |
Get current network sync status |
IsNetworkSyncLocalControlAllowed() |
Check if local control is allowed |
BroadcastCommand(ref command) |
Manually broadcast command (server only) |
NetworkSyncStatus Properties
| Property | Type | Description |
|---|---|---|
IsEnabled |
bool | Whether network sync is active |
IsServer |
bool | True if running as server |
IsClient |
bool | True if running as client |
ConnectionState |
ConnectionState | Current connection state (client only) |
ClientCount |
int | Number of connected clients (server only) |
AverageLatency |
double | Average network latency in ms (client only) |
IsLocalControlAllowed |
bool | Whether local playback control is allowed |
TimeSyncTier |
TimeSyncTier | Current time synchronization method |
Real-World Use Cases
🏠 Multi-Room Audio System
Whole-Home Audio
// Living Room (Server - Main Control)
await OwnaudioNet.StartNetworkSyncServerAsync();
var livingRoomTrack = new FileSource("party-mix.mp3");
mixer.AddSource(livingRoomTrack);
livingRoomTrack.Play();
// Kitchen (Client)
await OwnaudioNet.StartNetworkSyncClientAsync();
var kitchenTrack = new FileSource("party-mix.mp3");
mixer.AddSource(kitchenTrack);
// Automatically follows living room
// Bedroom (Client)
await OwnaudioNet.StartNetworkSyncClientAsync();
var bedroomTrack = new FileSource("party-mix.mp3");
mixer.AddSource(bedroomTrack);
// Automatically follows living room
// Perfect synchronization throughout your home!
🎤 Live Performance / DJ Setup
Professional DJ System
// Main Mixer (Server)
await OwnaudioNet.StartNetworkSyncServerAsync();
var mainOutput = new FileSource("set-track-01.mp3");
mixer.AddSource(mainOutput);
// Monitor Speakers (Clients)
// Multiple monitor positions all receive the same audio
await OwnaudioNet.StartNetworkSyncClientAsync();
// Backup System (Client)
// Ready for instant failover if main system fails
await OwnaudioNet.StartNetworkSyncClientAsync(
allowOfflinePlayback: true); // Continues if main fails
// All systems play in perfect sync
// Backup automatically takes over if main disconnects
🎬 Installation Art / Museums
Synchronized Installation
// Central Control Room (Server)
await OwnaudioNet.StartNetworkSyncServerAsync();
var soundtrack = new FileSource("installation-audio.wav");
mixer.AddSource(soundtrack);
// Multiple Display Zones (Clients)
// Zone 1, 2, 3, 4... all synchronized
for (int zone = 1; zone <= 10; zone++)
{
// Each zone runs on separate device
await OwnaudioNet.StartNetworkSyncClientAsync();
var zoneTrack = new FileSource("installation-audio.wav");
mixer.AddSource(zoneTrack);
}
// Synchronized audio-visual experience across entire installation
🎧 Collaborative Music Production
Studio Collaboration
// Producer's Workstation (Server)
await OwnaudioNet.StartNetworkSyncServerAsync();
var projectMix = new FileSource("project-mix.wav");
mixer.AddSource(projectMix);
// Musicians' Headphones (Clients)
// Guitarist
await OwnaudioNet.StartNetworkSyncClientAsync();
var guitaristMix = new FileSource("project-mix.wav");
mixer.AddSource(guitaristMix);
// Vocalist
await OwnaudioNet.StartNetworkSyncClientAsync();
var vocalistMix = new FileSource("project-mix.wav");
mixer.AddSource(vocalistMix);
// Everyone hears exactly the same thing at the same time
// Perfect for recording sessions and rehearsals
📱 Mobile Party Mode
Synchronized Mobile Devices
// Main Phone/Tablet (Server)
await OwnaudioNet.StartNetworkSyncServerAsync();
// Other Phones/Tablets (Clients)
await OwnaudioNet.StartNetworkSyncClientAsync(
serverAddress: null, // Auto-discovery on WiFi
allowOfflinePlayback: true);
// All devices play in perfect sync over WiFi
// Great for parties, outdoor events, etc.
Performance Characteristics
CPU Usage
| Component | CPU Usage | Priority | Impact |
|---|---|---|---|
| Audio MixThread | 8-10% | Highest | UNCHANGED ✅ |
| FileSource Decoders | 2-5% per track | Normal | UNCHANGED ✅ |
| Network Receive Thread | 1-2% | Normal | NEW |
| Network Send Thread (server) | 0.5-1% | Normal | NEW |
| Total Impact | +2-3% | - | Negligible ✅ |
Network Bandwidth
- Clock sync: ~100 bytes @ 100Hz = 10 KB/s per client
- Commands: ~50 bytes per command (negligible)
- Total: <15 KB/s per client (minimal)
Memory Footprint
- Server: ~2 MB (client tracking, command queue)
- Client: ~1 MB (receive buffer, state cache)
- Per-client overhead: ~100 KB (connection state)
- Steady-state: 0 heap allocations
Zero-GC Guarantees
| Operation | Allocation | Technique |
|---|---|---|
| Clock sync broadcast | 0 bytes | stackalloc, ArrayPool |
| Command serialization | 0 bytes | Span<byte>, BinaryPrimitives |
| Command deserialization | 0 bytes | ReadOnlySpan<byte> |
| State updates | 0 bytes | volatile fields, Interlocked |
Performance Guarantee
Network synchronization is designed to have ZERO impact on audio playback quality.
All performance-critical paths are zero-allocation and lock-free. Audio threads are never blocked
by network operations.
Troubleshooting
Common Issues
⚠️ Clients Not Discovering Server
- Ensure all devices are on the same local network
- Check firewall settings (UDP port 9876 must be open)
- Try specifying server IP manually instead of auto-discovery
- Verify router allows UDP broadcast/multicast
⚠️ Audio Drift / Desynchronization
- Check network latency (WiFi 2.4GHz can be unstable)
- Use wired Ethernet for best results (<5ms accuracy)
- Ensure all devices use identical audio files
- Verify sample rates match across all devices
⚠️ Connection Drops Frequently
- Check WiFi signal strength on all devices
- Reduce network congestion (pause downloads, streaming)
- Use 5GHz WiFi instead of 2.4GHz if available
- Consider using wired Ethernet for critical devices
Best Practices
- Use identical audio files - Same format, sample rate, and encoding
- Prefer wired connections - Ethernet provides best synchronization
- Use 5GHz WiFi - Lower latency than 2.4GHz
- Minimize network traffic - Pause other network-intensive applications
- Test before deployment - Verify synchronization in your specific environment
- Monitor connection state - Use events to detect and handle connection issues
Firewall Configuration
Required Firewall Rules
# Windows Firewall
netsh advfirewall firewall add rule name="OwnaudioSharp NetworkSync" dir=in action=allow protocol=UDP localport=9876
# Linux iptables
sudo iptables -A INPUT -p udp --dport 9876 -j ACCEPT
# macOS
# Allow in System Preferences > Security & Privacy > Firewall > Firewall Options
Need Help?
For additional support, check the GitHub repository
or open an issue with your specific use case.