This document outlines the plan to integrate LocalPlayer functionality into LyrPlay, enabling offline/cached audio playback for iOS users with poor cellular connectivity or data limitations.
- Source: LMS-Community/plugin-LocalPlayer (Triode's original work)
- Purpose: Enables same-machine file access for Squeezelite players
- Key Finding: NO caching logic - only direct file system access
- Mechanism:
- Players report
'loc'as last format capability - LMS returns
file://127.0.0.1:3483/URLs instead of HTTP streams - Players convert these back to local file paths
- Players report
The forum discussion about "caching and transcoding like PlexAmp" was proposing to extend the LocalPlayer concept to add downloading/caching for remote players - functionality that doesn't exist yet.
- Built-in file:// URL support:
STKAudioPlayerautomatically detectsfile://scheme - Dedicated local file handler: Uses
STKLocalFileDataSourcefor local files - Format support: Relies on Core Audio codecs (supports FLAC through system)
- No code changes needed: Current
audioPlayer.play(url)works with file:// URLs
// From STKAudioPlayer.m line 671-673
if ([url.scheme isEqualToString:@"file"])
{
retval = [[STKLocalFileDataSource alloc] initWithFilePath:url.path];
}- FLAC extension not in explicit file type mapping (returns hint 0)
- Core Audio handles format detection automatically
- Should work seamlessly with cached FLAC files
- SlimProto capabilities: Already declares formats in HELO message
- Stream handling: Robust
strmcommand processing with URL extraction - Format support: Handles FLAC, AAC, MP3, ALAC, PCM correctly
- StreamingKit integration: Uses
audioPlayer.play(url)- works with local files
- HELO message: Add
'loc'to capabilities string (line 280 in SlimProtoClient.swift) - Stream command handler: Detect
file://127.0.0.1:3483/URLs in handleStartCommand - Audio pipeline: No changes needed - StreamingKit handles both HTTP and file:// URLs
- Update capabilities string:
// In SlimProtoClient.swift line 280
let capabilities = "Model=squeezelite,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Balance=1,Firmware=v1.0.0-iOS,ModelName=SqueezeLite,MaxSampleRate=48000,flc,aac,mp3,loc"- Add URL detection in SlimProtoCommandHandler.swift:
private func handleStartCommand(url: String, format: String, startTime: Double) {
if url.hasPrefix("file://127.0.0.1:3483/") {
// LocalPlayer mode - extract original file URL
let originalURL = String(url.dropFirst("file://127.0.0.1:3483/".count))
handleLocalFilePlayback(originalURL: originalURL, format: format, startTime: startTime)
} else {
// Normal streaming mode - existing code unchanged
coordinator?.playStream(url: url, format: format, startTime: startTime)
}
}- Add local file handler:
private func handleLocalFilePlayback(originalURL: String, format: String, startTime: Double) {
Task {
if let cachedFileURL = await getCachedFile(originalURL) {
// Play cached file using StreamingKit (no changes to audio pipeline)
coordinator?.playStream(url: cachedFileURL.absoluteString, format: format, startTime: startTime)
} else {
// Download and cache first, then play
if let downloadedFileURL = await downloadAndCacheFile(originalURL) {
coordinator?.playStream(url: downloadedFileURL.absoluteString, format: format, startTime: startTime)
} else {
// Fallback to streaming if download fails
coordinator?.playStream(url: originalURL, format: format, startTime: startTime)
}
}
}
}- ✅ No breaking changes: Existing streaming functionality unchanged
- ✅ Same audio pipeline: StreamingKit handles both HTTP and file:// URLs
- ✅ Preserved integrations: Lock screen, Now Playing, audio session management all work
- ✅ FLAC seeking fix preserved: Server-side transcoding still works for streaming
- Only affects LocalPlayer-enabled servers with 'loc' plugin setting
- Fallback to normal streaming if anything fails
- No changes to core audio handling
-
LyrPlayCacheManager class:
- Download files from LMS server
- Manage cache directory in iOS Documents folder
- Handle cache size limits and cleanup
- Track usage patterns for smart cleanup
-
Storage considerations:
- Default cache size: 10GB (user configurable)
- Location: iOS Documents directory (user accessible via Files app)
- Format preservation: Download original format (FLAC stays FLAC)
- Metadata storage: Track file info, usage stats, download dates
-
Download strategy:
- On-demand downloading when LocalPlayer URL received
- Pre-caching of queue (next 3-5 songs)
- Background downloading on WiFi only (user setting)
- Resume interrupted downloads
class LyrPlayCacheManager {
private let cacheDirectory: URL
private let maxCacheSize: Int64
private let downloadSession: URLSession
func getCachedFile(_ originalURL: String) async -> URL? {
// Check if file exists in cache
// Return file:// URL if found
}
func downloadAndCacheFile(_ originalURL: String) async -> URL? {
// Download from LMS server
// Save with proper file extension (.flac, .mp3, etc.)
// Update metadata and usage tracking
// Return file:// URL when complete
}
func preCacheQueue(_ urls: [String]) async {
// Background download of upcoming songs
// WiFi-only option
// Respect cache size limits
}
func cleanupCache() {
// Remove oldest/least-used files
// Respect user preferences
// Maintain cache size under limit
}
}-
Pre-caching Queue Management:
- Monitor SlimProto queue changes
- Automatically download next 3-5 songs
- Cancel downloads for removed queue items
-
Smart Cache Management:
- LRU (Least Recently Used) cleanup
- Pin favorite albums for offline
- Usage statistics and recommendations
-
User Interface Enhancements:
- Cache status in settings
- Manual download options
- Offline mode indicator
- Cache size and usage display
-
Network Optimization:
- WiFi-only downloading
- Pause downloads on cellular
- Resume interrupted downloads
- Parallel downloads with rate limiting
-
Verify LocalPlayer plugin on LMS server:
- Install plugin and enable 'loc' setting
- Confirm server sends file:// URLs to LyrPlay
-
Test StreamingKit local file playback:
- Create test FLAC, MP3, AAC files in iOS simulator
- Verify
audioPlayer.play(fileURL)works correctly - Test seeking functionality with local FLAC files
-
Integration testing:
- Test with and without LocalPlayer plugin
- Verify fallback to streaming works
- Confirm no impact on existing functionality
-
Download and caching:
- Test download of various formats
- Verify cache management and cleanup
- Test cache size limits
-
Error handling:
- Network failures during download
- Disk space exhaustion
- Corrupted cache files
- FLAC format detection: StreamingKit should handle via Core Audio
- Mitigation: Test with actual FLAC files, verify playback
- URL parsing edge cases: Malformed file:// URLs
- Mitigation: Robust error handling with fallback to streaming
- iOS storage limitations: Cache size vs available space
- Mitigation: Dynamic cache size limits, user controls
- Background download restrictions: iOS background task limits
- Mitigation: Foreground downloading, WiFi-only options
- No high-risk changes due to non-breaking, additive approach
- StreamingKit local file playback verified
- LocalPlayer URLs detected and handled
- No regression in existing streaming functionality
- FLAC files play correctly from cache
- Files download and cache successfully
- Cache management respects size limits
- Smart cleanup maintains frequently used files
- Background downloading works on WiFi
- Queue pre-caching reduces buffering
- User interface provides cache control
- Offline mode works without network
- Battery impact remains acceptable
Recommendation: Proceed with Phase 1
The research confirms that StreamingKit fully supports local file playback through its built-in STKLocalFileDataSource. The integration can be implemented with minimal risk using a non-breaking, additive approach that preserves all existing functionality while adding powerful offline capabilities for mobile users.
The phased approach allows for incremental development and testing, with each phase building on the previous one while maintaining system stability.
Last Updated: July 29, 2025
Status: Ready for Phase 1 implementation