Skip to content

feat: add comprehensive examples suite#5

Open
harperreed wants to merge 16 commits intomainfrom
feat/examples-suite
Open

feat: add comprehensive examples suite#5
harperreed wants to merge 16 commits intomainfrom
feat/examples-suite

Conversation

@harperreed
Copy link
Collaborator

Summary

  • Add 6 standalone feature showcase examples for SendspinKit
  • Add root Examples/README.md with quick start guide and learning path
  • Extend SendspinKit API to expose clock synchronization stats

New Examples

Example Feature Demonstrated
DiscoveryExample mDNS/Bonjour server discovery
MetadataClient Display-only client (metadata@v1 role)
ControllerClient Silent player pattern for volume/mute control
MultiCodecPlayer PCM/Opus/FLAC format negotiation
ErrorRecovery Exponential backoff, error classification
ClockSyncDiagnostics NTP-style clock sync stats

Key Characteristics

  • All examples use consistent CLI patterns (ArgumentParser)
  • Self-contained - each can be copied as a starting point
  • Teaching-quality comments explaining "why"
  • Comprehensive READMEs per example
  • No mocks - real server required

API Changes

  • Added getClockStats() method to SendspinClient
  • Extended ClockStats struct with drift and sampleCount fields

Test plan

  • All examples build successfully
  • Test each example against running Sendspin server
  • Verify discovery works on local network
  • Test codec negotiation with different server configs

🤖 Generated with Claude Code

harperreed and others added 16 commits December 17, 2025 22:26
Design for 6 standalone feature showcase examples:
- DiscoveryExample, MetadataClient, ControllerClient
- MultiCodecPlayer, ErrorRecovery, ClockSyncDiagnostics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements a standalone Swift package that shows how to discover Sendspin
servers on the local network using mDNS/Bonjour.

Features:
- ArgumentParser CLI with --timeout and --verbose flags
- Clean output showing server name, URL, hostname, port
- Display of metadata from TXT records in verbose mode
- Exit codes: 0 for success (servers found), 1 for failure (none found)
- Comprehensive README with usage examples and troubleshooting

The example follows the CLIPlayer pattern with Package.swift referencing
SendspinKit via relative path and includes teaching-quality comments
explaining the why behind each operation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents .build directory from being tracked in version control.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements a metadata-only client demonstrating:
- Connecting with metadata@v1 role (no audio playback)
- Auto-discovery via mDNS or manual server URL
- Real-time metadata display (title, artist, album, duration)
- Teaching-quality comments explaining async event streams
- ArgumentParser CLI with validation
- Clean console output without TUI complexity

This example showcases:
- Role-based capability negotiation
- Resource-efficient metadata-only consumption
- Async stream event handling patterns
- Server discovery integration
- Change detection to avoid duplicate displays

Perfect for display screens, monitoring systems, or lightweight
integrations that need track info without audio.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements a "silent player" that demonstrates playback control without
local audio output. This example shows:

- Using player@v1 role with minimal configuration
- Sending volume and mute control commands via SendspinClient API
- Interactive keyboard control with raw terminal input
- Metadata monitoring to show what's playing
- Silent operation (audio received but not consumed)

The example clarifies that controller@v1 role is reserved for future
server-coordinated multi-room control, while the current use case
(controlling your own playback without audio output) uses the player
role as a "silent player".

Control methods available in SendspinClient API:
- setVolume(_ volume: Float) - Set volume from 0.0 to 1.0
- setMute(_ muted: Bool) - Set mute state

Files created:
- Examples/ControllerClient/Package.swift
- Examples/ControllerClient/Sources/ControllerClient/main.swift
- Examples/ControllerClient/README.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed "controller@v1" to "player@v1 + metadata@v1" to accurately
reflect the silent player pattern implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement a comprehensive example showing how to negotiate audio formats
with SendspinKit servers. This example demonstrates:

- Creating PlayerConfiguration with multiple AudioFormatSpec in priority order
- Observing which format the server negotiates via .streamStarted event
- Supporting hi-res audio formats (up to 384kHz/32-bit)
- Comparing requested formats vs. negotiated format
- Understanding codec tradeoffs (Opus, FLAC, PCM)

The example includes:
- ArgumentParser CLI with flexible options
- Server discovery or direct connection
- Configurable codec preferences (--prefer)
- Configurable sample rate and bit depth
- Session duration control
- Rich output showing negotiation details and codec characteristics

Files created:
- Examples/MultiCodecPlayer/Package.swift
- Examples/MultiCodecPlayer/Sources/MultiCodecPlayer/main.swift
- Examples/MultiCodecPlayer/README.md

This example is particularly useful for understanding:
- How supportedFormats array priority affects negotiation
- What happens when server doesn't support preferred format
- Hi-res audio support capabilities
- Bitrate calculations for different formats

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…terns

Implements comprehensive error handling and reconnection logic example
that demonstrates production-ready resilience patterns for SendspinKit
clients.

Key features:
- Exponential backoff with jitter to prevent thundering herd
- Connection state machine tracking lifecycle transitions
- Error classification (retryable vs non-retryable)
- Circuit breaker pattern with max retry limits
- Graceful shutdown handling (SIGINT)
- Detailed logging of state transitions and timing
- Configurable retry behavior via CLI arguments

Teaching points:
- When to retry vs when to give up
- How to avoid overwhelming recovering servers
- State machine design for connection management
- Error categorization for smart retry logic
- Production monitoring and debugging practices

Usage:
  swift run ErrorRecovery --server ws://localhost:8927
  swift run ErrorRecovery --discover --max-retries 10 --retry-delay 2.0

Files created:
- Examples/ErrorRecovery/Package.swift
- Examples/ErrorRecovery/Sources/ErrorRecovery/main.swift
- Examples/ErrorRecovery/README.md

The example includes comprehensive documentation with test scenarios,
backoff calculation tables, and production recommendations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix shutdown race condition by awaiting event task cancellation
- Add non-retryable error cases for teaching completeness
- Distinguish unknown errors with warning symbol

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ClockSyncDiagnostics example package
  - Real-time display of clock synchronization metrics
  - Shows offset, RTT, drift rate, and quality indicators
  - Educational output explaining what the numbers mean
  - Supports server discovery and direct connection
  - Configurable display refresh interval

- Expose clock synchronization statistics via SendspinClient
  - Add getClockStats() method to SendspinClient
  - Extend ClockStats struct to include drift and sampleCount
  - Allows monitoring of sync quality from client applications

- Comprehensive README documenting:
  - NTP-style 4-way handshake protocol
  - Kalman filter drift compensation
  - Why sub-millisecond sync matters for multi-room audio
  - How to interpret RTT, offset, and drift metrics

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Provides quick start guide, examples table, common CLI patterns,
learning path recommendations, and contribution guidelines.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove all .build/ directories from git tracking
- Add .gitignore to MultiCodecPlayer

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant