DLNA POSITION TRACKING:
- Added GetPositionInfo SOAP action to query current playback position
- Added GetTransportInfo SOAP action to get transport state (PLAYING/PAUSED/STOPPED)
- New dlna_get_position command returns position, duration, and transport state
- Added parse_time_string() helper for HH:MM:SS format
FRONTEND INTEGRATION:
- castStore: Added position polling (1s interval) when connected to DLNA
- castStore: New getCastPosition() for UI components
- castStore: Automatic polling start/stop on track play/disconnect
- playerStore: Subscribes to castStore for position updates
- playerStore: Updates currentTime from cast position when casting
This enables the seekbar to display accurate position during DLNA playback.
Seek functionality was already implemented (dlna_seek command).
Files modified:
- src-tauri/src/cast/dlna/device.rs
- src-tauri/src/cast/dlna/commands.rs
- src-tauri/src/cast/dlna/mod.rs
- src-tauri/src/lib.rs
- src/lib/stores/castStore.ts
- src/lib/stores/playerStore.ts
PROBLEM:
- DLNA device detection and connection worked
- Audio playback on DLNA devices did not work
ROOT CAUSE:
- DIDL-Lite metadata had hardcoded protocolInfo='audio/flac'
- Many DLNA devices silently reject content when protocolInfo
doesn't match the actual MIME type
- No debug logging to diagnose SOAP action failures
FIX:
- Pass actual content_type from Qobuz stream to DIDL builder
- Generate protocolInfo dynamically based on real MIME type
- Add extensive debug logging for:
- MediaServer URL generated
- Content-Type from Qobuz
- Complete DIDL-Lite metadata
- SOAP action responses (SetAVTransportURI, Play)
- Error details when actions fail
Files modified:
- src-tauri/src/cast/dlna/device.rs
- src-tauri/src/cast/dlna/commands.rs
The media server was starting at app launch and polling every 250ms
even when not using Chromecast/DLNA casting. Now it only starts when
the user actually tries to cast audio.
Frontend:
- Add castStore for managing cast state (connect, disconnect, play, pause, etc)
- Update CastPicker to use castStore, show connected device banner with disconnect
- Wire isCastConnected to NowPlayingBar and ExpandedPlayer for visual indicator
- Modify playbackService to cast when connected instead of local playback
DLNA Backend:
- Implement full AVTransport SOAP client with:
- SetAVTransportURI with DIDL-Lite metadata
- Play, Pause, Stop, Seek actions
- RenderingControl SetVolume
- Add dlna_play_track command that fetches stream, downloads audio, and serves via media server
- Share media server between Chromecast and DLNA
Import Chromecast, AirPlay, and DLNA casting scaffolding from separate
branches. The module is currently disabled due to:
- Thread safety issues: rust_cast uses Rc internally (not Send)
- API compatibility: rupnp methods have changed
The scaffolding includes:
- Chromecast: mDNS discovery, device connection, media server
- AirPlay: Discovery scaffolding (RAOP playback pending)
- DLNA/UPnP: SSDP discovery scaffolding (playback pending)
To enable casting in the future:
1. Fix rust_cast thread safety (or use spawn_blocking)
2. Update rupnp API calls for current version
3. Add Deserialize derive to metadata types
4. Uncomment cast module in lib.rs
5. Wire up commands in invoke_handler