Pure Swift Moonlight-compatible client stack for Apple platforms.
This package focuses on protocol, transport, media, input, and runtime orchestration for Sunshine and Apollo hosts. App UI is intentionally kept outside the core library so consumers can build their own SwiftUI, UIKit, AppKit, or game-surface integrations.
Experimental. The package builds, has a broad headless test suite, and includes live-host smoke/capture tooling, but it is not a production-ready Moonlight client yet. Public APIs may change while interoperability gaps are closed.
See docs/PARITY_ROADMAP.md for the current production-readiness matrix.
- Pure Swift client/session API for Apple platforms
- Sunshine and Apollo host model with compatibility profiles and host quirks
- Bonjour discovery plus manual host entry
- Host info, app list, launch, RTSP negotiation, and UDP channel establishment
- Crypto-backed pairing with RSA identity persistence
- Apollo OTP-assisted pairing support
- Control-channel parsing and encrypted control framing
- Video/audio packet ingest with RTP/bare packet parsing and loss metrics
- VideoToolbox-first decode path with a pluggable fallback decoder boundary
- Metal renderer with SDR, HDR metadata, EDR opt-in, and presentation geometry helpers
- Opus decoder and AVAudioEngine-backed audio sink
- Semantic input encoding for mouse, keyboard, touch, pen, and controllers
- GameController integration boundary for Xbox and DualSense-class controllers
- Headless
swift-moonlight-smokeandswift-moonlight-capturetools for real-host verification - macOS SwiftUI test app for local interoperability testing
- iOS 17+
- macOS 14+
- tvOS 17+
- Swift tools 6.0+
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/wiedymi/swift-moonlight.git", branch: "main")
]Then add the library target:
.target(
name: "YourApp",
dependencies: [
"SwiftMoonlight"
]
)import Foundation
import SwiftMoonlight
let storageDirectory = URL(filePath: "/path/to/app-support/swift-moonlight")
try FileManager.default.createDirectory(
at: storageDirectory,
withIntermediateDirectories: true
)
let configuration = try ProductionClientFactory.configuration(
storageDirectory: storageDirectory,
displayName: "My Moonlight App",
credentialStorage: .keychain(.init(service: "com.example.moonlight"))
)
let client = MoonlightClient(configuration: configuration)
let host = try await client.addHost(
.init(address: "192.0.2.50", port: 47989)
)
try await client.pair(hostID: host.id, pin: "1234")
let apps = try await client.fetchApps(hostID: host.id)
let desktop = apps.first { $0.name == "Desktop" } ?? apps[0]
let session = try await client.openSession(
hostID: host.id,
appID: desktop.id,
configuration: .default1080p60
)
let runtime = try await client.prepareRuntime(for: session, hostID: host.id)
runtime.runtime.start()
// Attach renderer/decoder/audio components before or immediately after runtime startup.
// On Apple platforms, `AppleMediaComponents.attachRecommendedPlaybackComponents(...)`
// wires VideoToolbox, Metal, Opus, and AVAudioEngine for a CAMetalLayer surface.For a Metal-backed app surface:
#if canImport(Metal) && canImport(QuartzCore) && canImport(AVFoundation)
try await AppleMediaComponents.attachRecommendedPlaybackComponents(
to: session,
device: metalDevice,
layer: metalLayer,
preferredDecodeMode: .hardwareFirst
)
#endifswift testHeadless smoke test:
SWIFT_MOONLIGHT_TEST_HOST=192.0.2.50 \
SWIFT_MOONLIGHT_TEST_PIN=1234 \
SWIFT_MOONLIGHT_TEST_APP_ID=desktop \
swift run swift-moonlight-smokeHeadless capture:
SWIFT_MOONLIGHT_TEST_HOST=192.0.2.50 \
SWIFT_MOONLIGHT_TEST_APP_ID=desktop \
SWIFT_MOONLIGHT_CAPTURE_DYNAMIC_RANGE=hdr \
SWIFT_MOONLIGHT_CAPTURE_CODECS=hevc,h264 \
swift run swift-moonlight-captureManual macOS test app:
./scripts/build-test-app.shOr generate and open the Xcode project:
./scripts/build-test-app.sh --open-projectdocs/SPEC.md- implementation scope and acceptance criteriadocs/ARCHITECTURE.md- module boundaries and dependency directiondocs/PARITY_ROADMAP.md- current production-readiness matrixdocs/HEADLESS_TESTING.md- smoke, capture, and fixture strategydocs/FIXTURES.md- fixture inventory and provenance rulesdocs/BINARY_LAYOUTS.md- index for exact packet layout docsdocs/OBSERVED_BEHAVIORS.md- clean-room notes for undocumented host behaviordocs/APOLLO_COMPATIBILITY.md- Apollo-specific compatibility notesdocs/api/- developer-facing API contractsdocs/protocol/- protocol sequencing notesdocs/binary/- packet and binary layout notes
refs/contains upstream reference repositories as git submodules for behavioral study only.- This repository is a clean-room Swift implementation under MIT. Do not copy, paste, or mechanically port GPL reference code.
- Opus is bundled as
Vendor/COpus.xcframeworkand can be rebuilt with./scripts/build-opus-xcframework.sh. - ENet is vendored under
Vendor/ENet.
MIT