Full radio control on iOS and Android — built with .NET MAUI. Operate your shack from anywhere: on the home Wi-Fi the app auto-detects the server and uses the lowest-latency LAN path; off-network, type your tunnel URL and the app switches to the auth-gated unified WebSocket. Same UI, same features, every platform.
💡 Key Features
Operate From Anywhere
Auto-detect picks the LAN multi-port path at home; manual hostname switches to the unified-WebSocket transport for remote access through Cloudflare Tunnel, Tailscale Funnel, nginx, or a port-forward. HMAC-SHA-256 secret stored in platform secure storage (Keychain on iOS, EncryptedSharedPreferences on Android).
Frequency & Mode Control
Large LCD-style display, segment-tap up / down buttons, manual keyboard entry, rotary VFO knob overlay. Modes: LSB, USB, CW-L, CW-U, AM, FM, DIG-L, DIG-U with per-band smart step sizes.
Multi-Rig Support
Switch between up to 4 OmniRig rigs with custom names. VFO A/B, Split, RIT, XIT all bidirectional with the radio.
Dual Audio Streams
Low-latency 12 kHz PCM (~150 ms) for live tuning + 192 kbps stereo HiFi MP3 for SSB / AM listening on cellular. Platform-native decode (Android MediaCodec, iOS AVPlayer). Mutually exclusive; auto-switches to 12 kHz on TX.
Eight Digital Decoders
CW (40+ WPM), RTTY (auto-detect baud + shift, two demod algorithms with picker), PSK31 (9 BPSK / QPSK variants with AFC and FEC), FT8 / FT4 (color-coded by SNR), SSTV (19 modes with image canvas + waterfall), WEFAX (weather-fax decoder), NAVTEX (SITOR-B maritime safety), and APRS (AX.25 packet radio).
Transmit Support
Chat-style timeline of incoming + outgoing. Voice (tap-to-toggle PTT), CW, RTTY, PSK31, APRS. Server enforces a single-owner lock; rejected sends are visually greyed.
SDR Panadapter
Live scope + scrolling waterfall (SkiaSharp). Multi-SDR slot picker and Audio button when multiple devices are active. Tap-to-tune, drag-pan with comfort zone, RF / IF mode, FFT size picker (4K–32K). Same wire format as the desktop, server, and HA cards.
Audio Visualization
4 modes (Waterfall + spectrum overlay, Spectrum bars, Spectrum LED, Oscilloscope) with 6 themes, peak-hold colors, gain / contrast / range sliders. Same math as the desktop client — visual parity guaranteed.
Memory Bank
90 local slots paginated 10×9 (long-press to save, tap to recall). Per-band band navigation across HF / VHF / UHF amateur and broadcast allocations.
Audio Recording
Save audio sessions locally with frequency / mode / timestamp filenames.
Auto-Reconnect
Resumes streaming, decoder subscriptions, and TX state on network blips. Auth state recovered from secure storage so you don’t re-prompt every reconnect.
The SDR panadapter’s 3D waterfall — the live spectrum rendered as a rotatable, GPU-accelerated perspective terrain
📋 System Requirements
| Platform | Minimum Version | Notes |
|---|---|---|
| Android | Android 8.0 (API 26) | Most phones from 2017 onwards |
| iOS | iOS 14.0 | iPhone 6s+, iPad 5th gen+ |
| Network (LAN) | Wi-Fi or VPN | App auto-detects servers via UDP broadcast on port 8081 (broadcast includes name=<hostname>). Discovered servers appear in a Picker dropdown as HOSTNAME (IP). Connects on TCP 8080/8081/8082/8085 (legacy multi-port path). |
| Network (Remote) | Wi-Fi, cellular, anywhere | Manually enter the server’s hostname or tunnel URL — app switches to the unified-WebSocket transport on port 8084 with HMAC auth. One port-forward / Cloudflare Tunnel / Tailscale Funnel covers everything. |
🎮 User Interface
Connection Section
- Server picker – A dropdown (Picker) that automatically lists all discovered ShackLink servers on the LAN as HOSTNAME (IP). Selecting a server fills the IP and port fields. When multiple servers are running, all appear simultaneously. Servers that stop broadcasting disappear after 12 seconds.
- IP / hostname – LAN IP (e.g.
192.168.1.100) for the legacy multi-port path, or a hostname / tunnel URL (e.g.shacklink.example.com) to switch to the unified-WebSocket transport for remote access. Auto-filled when you pick a server from the dropdown. - Port –
8080for the legacy LAN path (auto-set on UDP discovery),8084for the unified-WebSocket remote path (auto-set when you type a hostname). - Auth secret – For the unified-WebSocket path, the app prompts for the HMAC-SHA-256 hex secret from the server’s Tools → Security panel. Stored in platform secure storage (Keychain on iOS, EncryptedSharedPreferences on Android).
- Connect Button – Tap to establish or close connection
- Status Indicator – Shows Connected/Disconnected state
Two Transports, One Protocol
The app automatically picks one of two transports based on how it found the server:
- LAN auto-detect → legacy multi-port — server’s UDP broadcast (including
name=<hostname>) reached the device. Discovered servers appear in the server Picker dropdown as HOSTNAME (IP). App connects on TCP 8080/8081/8082/8085. Lowest-latency path; preserved indefinitely for home use. - Manual hostname → unified WebSocket — you typed an address that didn’t come from UDP discovery (typical for remote access through Cloudflare Tunnel, Tailscale Funnel, etc.). App opens a single
wss://host:8084/wswith HMAC auth.
Either way, the radio control protocol is identical — the app’s view models don’t know which transport is in effect.
Frequency Display
The frequency is displayed in a split format for easy reading:
- MHz – Megahertz (e.g., 14)
- KHz – Kilohertz (e.g., 074)
- Hz – Hertz (e.g., 000)
Each section has up/down arrow buttons for adjustment. The step size varies by mode.
Mode Selection
Tap any mode button to change the operating mode. The selected mode is highlighted.
🌐 Band Selection
Pre-configured bands with frequency limits:
| Band | Frequency Range | Description |
|---|---|---|
| LW | 148.5 – 283.5 kHz | Long Wave broadcast |
| MW | 530 – 1700 kHz | Medium Wave (AM broadcast) |
| SW | 2.3 – 26.1 MHz | Short Wave broadcast |
| FM | 87.5 – 108 MHz | FM broadcast |
| VHF Air | 108 – 137 MHz | Aviation band |
| 2m Ham | 144 – 148 MHz | 2 meter amateur band |
| 70cm Ham | 420 – 450 MHz | 70 cm amateur band |
| HF LSB/USB | 1.8 – 30 MHz | HF amateur bands (SSB) |
| HF CW | 1.8 – 30 MHz | HF amateur bands (CW) |
The app remembers your last frequency in each band and restores it when you return.
💾 Memory Bank
- Save – Long-press an empty slot to store the current frequency and mode
- Recall – Tap any saved slot to jump the rig straight to that frequency and mode
- Capacity – 90 on-device slots, paginated 9 per page across 10 pages
- Labels – Name a slot so its button shows the station or net instead of the raw frequency
- Persistence – Held in platform secure storage on the device, independent of the server’s own 24-slot memory bank
Step Sizes by Mode
| Mode | Step Size |
|---|---|
| AM | 10 kHz |
| FM | 100 kHz |
| SW | 5 kHz |
| MW | 10 kHz |
| LW | 1 kHz |
| LSB/USB | 1 kHz |
| CW | 100 Hz |
📈 SDR Panadapter & Waterfall
The SDR page draws a live scope and scrolling waterfall from the server’s panadapter stream with SkiaSharp — the same SDL1 spectrum feed the desktop, web, and Home Assistant clients consume, so the picture matches on every surface. On iOS and Android the waterfall renders on the GPU (an SKGLView surface).
- Multi-SDR slot picker – When the server has multiple SDR devices active, a Slot picker and Audio button appear above the waterfall. Select a slot to view its spectrum; the Audio button is blue when that slot is the listening source and red when it is not — tap to switch. The audio-active slot is also marked [A]. Hidden when only one device is active.
- Per-slot memory – Gain, floor, contrast, reference level, zoom, palette, and the 2D / 3D choice are remembered separately for each slot; switching slots snaps the frequency scale to that slot’s current tuning.
- Center mode – When enabled, panning shifts the SDR band (LO changes, rig marker stays centered). When disabled, panning moves the rig frequency marker.
- Tap – In center mode, re-centers the band on the tapped frequency. In non-center mode, tunes the rig. Commands are routed to the selected slot.
- Pinch-to-zoom – Zoom into the spectrum. Two-finger drag simultaneously pans the band.
- Fullscreen – Double-tap for fullscreen with larger fonts and labels.
- Long press – Sets the demod offset marker.
- 3D waterfall (terrain view) – Toggle the waterfall between the flat 2D view and a rotatable 3D perspective terrain. Drag to orbit the camera. GPU-accelerated via an
SKGLViewsurface, with palette, style, fog, and shading options. - Waterfall Ref (max-level) – A Ref slider sets the top of the waterfall color scale so strong signals reach the top of the palette instead of being clipped below full scale.
🔢 Digital Decoders
The app includes server-side digital mode decoding for all eight modes — CW, RTTY, PSK31, FT8, SSTV, WEFAX, NAVTEX, and APRS. Switching mode broadcasts to every connected client.
Decode Modes
- CW (Morse) – Real-time CW decoding up to 40 WPM
- RTTY – Baudot decoding with auto-detect for baud rate and shift
- PSK31 – Phase Shift Keying; 9 modes (BPSK-31/63/125, QPSK-L/U-31/63/125 with FEC), AFC, center frequency 200–3000 Hz, and squelch
- FT8 – FT8/FT4 decodes relayed from an external WSJT-X instance running on the server machine (UDP port 2237)
- SSTV – Slow Scan TV image reception with thumbnail and detail views
- WEFAX – Weather facsimile decoder (IOC 576/288 at 60/120 LPM); same image-+-progress UI as SSTV
- NAVTEX – Maritime safety message decoder (SITOR-B FEC, 100 baud, 170 Hz shift). Decoded characters stream to the text display.
- APRS – AX.25 1200 baud Bell 202 AFSK packet radio. Decoded packets display source callsign, position, and beacon text.
FT8 Color Coding
FT8 messages are color-coded by signal strength (SNR) for easy identification:
| SNR Range | Color | Signal Quality |
|---|---|---|
| 0 dB and above | Bright Green | Strong signal |
| -10 to -1 dB | White | Moderate signal |
| -15 to -11 dB | Orange | Weak signal |
| Below -15 dB | Red | Very weak signal |
SSTV Image Decoder
The SSTV decoder displays images transmitted over radio:
- Thumbnail view – Small preview in the decoder panel
- Detail view – Tap thumbnail for full-size image
- Progress display – Shows decode progress percentage
- Mode detection – Auto-detects mode or use forced mode
- Save images – Save decoded images to device
Supported modes (19 total): Robot 36 / 72 / 8BW / 24BW, Martin M1 / M2, Scottie S1 / S2 / DX, PD 90 / 120 / 160 / 180 / 240 / 290, Wraase SC2-120 / SC2-180, Pasokon P3 / P5 / P7
💡 Tip
Server-side decoding is more accurate than client-side because it processes the original audio without network jitter or latency issues.
🔊 Transmit & Image TX
ShackLink Mobile is a full transmit client for the server’s shared TX engine. Incoming and outgoing traffic share one chat-style timeline; the server enforces a single-owner TX lock, so a send refused because another operator holds the key is greyed out rather than silently dropped.
- Voice – Tap-to-toggle PTT (tap once to key, again to unkey) streams mic audio to the server’s token-authenticated voice uplink. A three-zone VU meter tracks your level while keyed.
- CW / RTTY / PSK31 – Type into the compose box and send; the server’s encoders key the rig and mirror the transmitted text back into the timeline.
- APRS – Compose and send AX.25 packets through the server’s APRS encoder.
- Image TX – Pick a photo and transmit it over the air; the staged image previews before you commit the send.
🎶 Audio Visualization
The app includes a high-performance spectrum analyzer and waterfall display for real-time audio visualization:
Features
- Spectrum Analyzer – Smooth curve display showing audio frequency content with semi-transparent fill
- Waterfall Display – Scrolling spectrogram with color-coded signal intensity
- Gain Control – Adjustable sensitivity (0.5x to 10x) for optimal display
- Collapsible Panel – Tap header to expand/collapse the visualization
- Mode-Aware Bandwidth – Display range adapts to radio mode (CW: 0-1kHz, SSB: 0-3kHz, FM: 0-6kHz)
- 3D Waterfall (terrain view) – The waterfall can switch to a rotatable 3D perspective terrain rendered on the GPU. Drag to orbit the camera; a button toggles 2D / 3D. Style, fog, and shading options included.
- Waterfall Palettes – 8 color schemes from the unified
WaterfallPalette, shared across the 2D and 3D waterfalls and matched to the other ShackLink surfaces.
Color Scale
The waterfall uses a multi-color gradient to indicate signal strength:
| Color | Signal Strength |
|---|---|
| Dark Blue | Very weak / noise floor |
| Blue | Weak signals |
| Cyan | Moderate signals |
| Green | Good signals |
| Yellow | Strong signals |
| Orange | Very strong signals |
| Red | Peak signals |
| White | Maximum intensity |
Technical Details
- FFT Size – 512 samples for detailed frequency resolution
- Sample Rate – 12kHz audio stream from server
- Refresh Rate – 30 FPS for smooth animation
- Rendering – GPU-accelerated using SkiaSharp with direct bitmap manipulation
💡 Performance
The visualization uses SkiaSharp for GPU-accelerated rendering with direct pixel buffer access, providing smooth 30 FPS performance even on mobile devices.
🔌 Protocol Details
The mobile app communicates with the server using simple text commands over TCP:
Commands Sent by App
# Set frequency (Hz)
FREQ:14074000
# Set mode
MODE:USB
# Select rig
RIG:1
Messages Received from Server
# Frequency and mode update
RIG:1:FREQ:14074000;MODE:USB
# Radio status
RIG:1:RADIO:ONLINE:IC-7300
RIG:1:RADIO:OFFLINE
# Rig names
RIGS:Rig 1|Rig 2|Rig 3|Rig 4
🔧 Troubleshooting
Cannot Connect (LAN)
- Verify the server is running and radio is connected
- Check IP address is correct (server IP, not radio IP)
- Ensure your phone is on the same network as the server
- Check firewall allows ports 8080, 8081, 8082, 8084, 8085 (and UDP 8081 for auto-detect) — Tools → Configure Firewall on the server creates the rules automatically
Cannot Connect (Remote)
- Verify your tunnel / port-forward is reachable: open
http://your-tunnel-host:8084in a browser. The web client should load. If not, the network path is broken before the app even tries. - The unified-WebSocket transport needs
/wswith WebSocket Upgrade headers passed through. Cloudflare Tunnel, Tailscale Funnel, and a default nginx + Let’s Encrypt setup all handle this. Some “lite” reverse proxies strip the upgrade headers — check the proxy’s docs. - If you connect briefly then disconnect: the secret is wrong. Open Tools → Security on the server, copy the secret, and paste it into the auth-secret prompt that appears when you re-enter a manual hostname.
Connection Drops
- Move closer to your Wi-Fi router
- Check for network interference
- Disable battery optimization for the app
- The app will automatically try to reconnect
Frequency Not Changing
- Ensure radio shows “ONLINE” status on server
- Check OmniRig is properly connected to the radio
- Verify frequency is within the radio’s range
- Check VFO is not locked on the radio
App Crashes on Startup
- Update to the latest version
- Clear app data and restart
- Reinstall the application
- Check device meets minimum requirements