Skip to content

IFM Station — Desktop Broadcaster Studio

Professional desktop broadcasting application for originating live content into the IFM mesh. Native performance, system audio integration, multi-source mixing.


Overview

PropertyValue
Binaryifm-station
Packagepackages/ifm-station/
Coreifm-core via Tauri/N-API
UIReact + TypeScript (WebView)
PlatformsWindows, macOS, Linux (x64 + arm64)
Installcurl -fsSL https://ifm.sh/install-station.sh | bash

Features

Broadcast Studio

  • Multi-source audio mixer — Microphone, system audio, file playback, virtual inputs
  • Real-time Opus encoding — 48 kHz stereo, configurable bitrate (32–256 kbps)
  • Live monitoring — Latency-compensated headphone feed with VU meters
  • Recording — Local WAV/Opus archive of every broadcast session

Frequency Management

  • Create stations — Enter FM-style number (91.700) or name (music.lofi → auto-assigned)
  • Access control — Public / Protected (shared key) / Hidden (invite only)
  • Station persistence — Stations saved locally; reopen preserves frequency number
  • Multi-station — Run multiple stations simultaneously (tabbed interface)

Relay Network

  • Relay pool view — Live list of available relays (mDNS + DHT discovered)
  • Relay selection — Manual or automatic (closest by RTT)
  • Relay health — Latency, uptime, peer count per relay
  • Direct peer mode — Bypass relays for LAN-only broadcasts

Communication

  • Real-time chat — Text chat with all tuned listeners
  • File transfer — Drag-drop files to broadcast to frequency
  • Listener view — Live peer count, geographic map, connection quality

System Integration

  • System tray — Minimize to tray; broadcast continues

  • Global hotkeys — Push-to-talk, mute, next/prev track

  • Audio device selection — Per-source input/output device picker

  • Background mode — Close window → keeps broadcasting in tray

  • Screen & System Audio Recording permission (macOS) — the console's Window and Desktop Audio sources enumerate and capture targets through ScreenCaptureKit. macOS requires the Screen & System Audio Recording TCC permission; without it the source lists stay empty and the console shows the "IFM needs permission" hint. Steps:

    1. Apple menu → System SettingsPrivacy & Security (sidebar; scroll down if needed)
    2. Click Screen & System Audio Recording
    3. Toggle the ability to record on for IFM Station (you can allow both screen and audio, or just audio)
    4. To add the app manually, click Add below the list and navigate to IFM Station
    5. Quit and reopen IFM Station — the permission applies only after the app restarts

    The app ships NSScreenCaptureUsageDescription in src-tauri/Info.plist. On macOS 15+ (Sequoia) the grant only applies to a stable code identity — a bare target/debug dev executable is ad-hoc signed and its signature changes every rebuild, so granting it in System Settings never sticks. Run a real .app bundle (bun scripts/build.mjs --desktop ifm-station, or cargo tauri build --debug) and grant the permission to IFM Station.app. The console detects the dev-build case and explains this in the source picker. See docs/desktop-apps/README.mdAudio notes (macOS) for the full reference.


Architecture


User Flow

First Launch

Daily Use


Configuration

Stored in platform config dir:

  • macOS: ~/Library/Application Support/ifm-station/
  • Windows: %APPDATA%\ifm-station\
  • Linux: ~/.config/ifm-station/
toml
# config.toml
[identity]
private_key = "ed25519..."          # Generated on first run
public_key = "ed25519..."

[stations]
# Auto-saved per station
"91.700" = { name = "morning.show", access = "public", created = "2024-01-15" }
"92.300" = { name = "team.private", access = "protected", key_hash = "sha256..." }

[audio]
input_device = "default"            # or device ID
output_device = "default"
sample_rate = 48000
bitrate = 128000                    # bps

[relay]
auto_select = true                  # Pick closest by RTT
selected_relays = []                # Manual override: [peer_id, ...]
direct_peer_mode = false            # LAN only, no relays

[ui]
minimize_to_tray = true
global_hotkeys = true
theme = "system"                    # light/dark/system

Keyboard Shortcuts

ActionShortcut
Push-to-talk (hold)Space (configurable)
Toggle muteM
Next stationCtrl+Right / Cmd+Right
Previous stationCtrl+Left / Cmd+Left
Open/close windowCtrl+Shift+I / Cmd+Shift+I
Start/stop broadcastCtrl+Shift+Space / Cmd+Shift+Space
Open settingsCtrl+, / Cmd+,

CLI Flags

bash
ifm-station [OPTIONS]

Options:
  --station <FREQ>        Auto-tune to frequency on start
  --headless              No window, broadcast only (for CI/servers)
  --config <PATH>         Custom config file
  --log-level <LEVEL>     trace/debug/info/warn/error
  --version               Print version
  --help                  Show help

Development

bash
cd packages/ifm-station

# Install deps
bun install

# Dev mode (hot reload)
bun run tauri dev

# Build release
bun run tauri build

# Output: src-tauri/target/release/bundle/

Project Structure

packages/ifm-station/
├── src/
│   ├── App.tsx              # Main app, routing
│   ├── main.tsx             # Entry
│   ├── components/
│   │   ├── Studio/          # Mixer, monitor, controls
│   │   ├── Setup/           # Frequency creation wizard
│   │   ├── Stations/        # Station list, tabs
│   │   ├── RelayPool/       # Relay selection UI
│   │   ├── Chat/            # Chat panel
│   │   ├── FileTransfer/    # Drag-drop file broadcast
│   │   └── Header/          # Brand, status, tray menu
│   ├── hooks/
│   │   ├── useStation.ts    # Station state + actions
│   │   ├── useMixer.ts      # Audio mixer state
│   │   ├── useRelayPool.ts  # Relay discovery + selection
│   │   └── useTray.ts       # System tray integration
│   ├── lib/
│   │   ├── ifm.ts           # Tauri command wrappers
│   │   ├── audio.ts         # AudioContext helpers
│   │   └── storage.ts       # Config persistence
│   └── styles/
│       ├── globals.css
│       └── variables.css
├── src-tauri/
│   ├── Cargo.toml
│   ├── tauri.conf.json
│   ├── src/
│   │   ├── main.rs          # Tauri entry, command registration
│   │   ├── commands/        # Individual command modules
│   │   │   ├── node.rs
│   │   │   ├── audio.rs
│   │   │   ├── mixer.rs
│   │   │   ├── discovery.rs
│   │   │   ├── config.rs
│   │   │   └── tray.rs
│   │   └── lib.rs           # Shared types, error handling
│   └── icons/               # App icons (png, icns, ico)
├── package.json
├── tauri.conf.json
└── vite.config.ts

Release Artifacts

PlatformFormatSize (est.)
macOS arm64.dmg~25 MB
macOS x64.dmg~28 MB
Windows x64.msi~30 MB
Windows arm64.msi~28 MB
Linux x64.AppImage~35 MB
Linux arm64.AppImage~32 MB
Linux x64.deb~12 MB
Linux x64.rpm~12 MB

All signed, notarized (macOS), cosign-verified.


Released under the MIT License.