### Initialize and Start Host Service (macOS) Source: https://github.com/ethanlipnik/miragekit/blob/main/README.md Set up and start the MirageHostService on a macOS host. Implement the MirageHostDelegate protocol to handle client connection requests. ```swift import MirageKitHost @MainActor final class HostController: MirageHostDelegate { private let hostService = MirageHostService() init() { hostService.delegate = self } func start() async throws { try await hostService.start() } func hostService(_ service: MirageHostService, shouldAllowClient client: MirageConnectedClient, toStreamWindow window: MirageWindow) -> Bool { true } } ``` -------------------------------- ### MirageInputEvent Examples Source: https://context7.com/ethanlipnik/miragekit/llms.txt Demonstrates various unified input event types for mouse, keyboard, scroll, and gesture forwarding. Use these to simulate user interactions on the remote stream. ```swift import MirageKit // Keyboard events let keyDown = MirageInputEvent.keyDown(MirageKeyEvent( keyCode: 0x00, // 'A' key characters: "a", charactersIgnoringModifiers: "a", modifiers: [], isRepeat: false )) // Mouse events with normalized coordinates (0.0-1.0) let click = MirageInputEvent.mouseDown(MirageMouseEvent( location: CGPoint(x: 0.5, y: 0.5), // Center of stream button: .left, clickCount: 1, modifiers: [] )) // Scroll events let scroll = MirageInputEvent.scrollWheel(MirageScrollEvent( location: CGPoint(x: 0.5, y: 0.5), deltaX: 0, deltaY: -10, // Scroll up phase: .changed, momentumPhase: .none, modifiers: [], isDirectionInverted: false )) // Magnify gesture let pinch = MirageInputEvent.magnify(MirageMagnifyEvent( magnification: 1.5, phase: .changed, modifiers: [] )) // Rotate gesture let rotate = MirageInputEvent.rotate(MirageRotateEvent( rotation: 45.0, // degrees phase: .changed, modifiers: [] )) // Send input to host clientService.sendInputFireAndForget(keyDown, forStream: streamID) ``` -------------------------------- ### MirageHostService Usage Source: https://context7.com/ethanlipnik/miragekit/llms.txt Demonstrates how to initialize and use `MirageHostService` to start and stop hosting window and desktop streams on macOS. It includes configuration options and delegate methods for managing client connections and input events. ```APIDOC ## MirageHostService API ### Description The `MirageHostService` is the primary class for hosting window and desktop streams from a macOS host. It manages client connections, screen capture, video encoding, and forwarding input events from clients back to the host. ### Method `MirageHostService` is initialized with configuration options and its delegate is set to handle callbacks. ### Endpoint Not applicable for this service class, as it operates locally on the host machine and advertises via Bonjour. ### Parameters #### Initialization Parameters - **hostName** (String) - Required - The name to advertise for the host. - **encoderConfiguration** (EncoderConfiguration) - Optional - Configuration for video encoding (e.g., `.highQuality`). - **loomConfiguration** (LoomConfiguration) - Optional - Configuration for the Loom networking framework (e.g., `.default`). #### Delegate Properties - **delegate** (MirageHostDelegate) - Required - An object conforming to `MirageHostDelegate` to receive service events. - **trustProvider** (TrustProvider) - Optional - A provider to approve or reject incoming connections. #### Feature Flags - **sharedClipboardEnabled** (Bool) - Optional - Enables clipboard sharing between host and clients. - **lightsOutEnabled** (Bool) - Optional - Enables a screen curtain on the host while streaming. - **muteLocalAudioWhileStreaming** (Bool) - Optional - Mutes the host's local audio during streaming. ### Methods - **start() async throws**: Starts the host service, making it discoverable via Bonjour and ready to accept connections. - **stop() async**: Stops the host service and cleans up resources. ### Delegate Methods - **hostService(_:shouldAcceptConnectionFrom:origin:completion:)**: Called when a client attempts to connect. The delegate must call the completion handler with `true` to accept or `false` to reject. - **hostService(_:didConnectClient:)**: Called when a client successfully connects. - **hostService(_:didDisconnectClient:)**: Called when a client disconnects. - **hostService(_:didReceiveInputEvent:forWindow:fromClient:)**: Called when the host receives an input event from a connected client. - **hostService(_:sessionStateChanged:)**: Called when the host's session availability state changes (e.g., system sleep/wake). ### Request Example ```swift import MirageKitHost @MainActor final class HostController: MirageHostDelegate { private let hostService: MirageHostService init() { hostService = MirageHostService( hostName: "My Mac", encoderConfiguration: .highQuality, loomConfiguration: .default ) hostService.delegate = self hostService.trustProvider = myTrustProvider // Assuming myTrustProvider is defined elsewhere hostService.sharedClipboardEnabled = true hostService.lightsOutEnabled = true hostService.muteLocalAudioWhileStreaming = true } func start() async throws { try await hostService.start() } func stop() async { await hostService.stop() } // MARK: - MirageHostDelegate func hostService( _ service: MirageHostService, shouldAcceptConnectionFrom deviceInfo: LoomPeerDeviceInfo, origin: MirageHostConnectionOrigin, completion: @escaping @Sendable (Bool) -> Void ) { completion(true) // Approve all connections } func hostService(_ service: MirageHostService, didConnectClient client: MirageConnectedClient) { print("Client connected: \(client.name)") } func hostService(_ service: MirageHostService, didDisconnectClient client: MirageConnectedClient) { print("Client disconnected: \(client.name)") } func hostService( _ service: MirageHostService, didReceiveInputEvent event: MirageInputEvent, forWindow window: MirageWindow, fromClient client: MirageConnectedClient ) { // Handle input events } func hostService(_ service: MirageHostService, sessionStateChanged state: LoomSessionAvailability) { // Handle session state changes } } ``` ### Response Success responses are indicated by the successful execution of methods and delegate callbacks. Errors are typically thrown by `start()` or handled via delegate methods. #### Success Response (200) Not directly applicable as methods are asynchronous or delegate-based. Successful connection establishment is indicated by `didConnectClient`. #### Response Example No direct response body for service methods. Delegate callbacks provide status updates. ``` -------------------------------- ### MirageEncoderOverrides for Stream Customization Source: https://context7.com/ethanlipnik/miragekit/llms.txt Client-supplied encoder overrides for per-stream customization, including codec, frame rate, bitrate, and resolution. Use to apply specific encoding settings when starting a desktop stream. ```swift import MirageKit import MirageKitClient let overrides = MirageEncoderOverrides( codec: .hevc, keyFrameInterval: 3600, colorDepth: .pro, captureQueueDepth: 8, bitrate: 100_000_000, latencyMode: .lowestLatency, performanceMode: .standard, allowRuntimeQualityAdjustment: true, encoderMaxWidth: 2560, encoderMaxHeight: 1440, upscalingMode: .spatial // MetalFX spatial upscaling ) // Apply to desktop stream try await clientService.startDesktopStream( width: 2560, height: 1440, streamMode: .unified, cursorPresentation: .simulatedCursor, encoderOverrides: overrides ) ``` -------------------------------- ### Initialize and Configure MirageHostService Source: https://context7.com/ethanlipnik/miragekit/llms.txt Initialize the MirageHostService with host name, encoder, and Loom configurations. Set up a trust provider and enable desired features like shared clipboard and screen curtain. ```swift import MirageKitHost @MainActor final class HostController: MirageHostDelegate { private let hostService: MirageHostService init() { // Initialize with optional configuration hostService = MirageHostService( hostName: "My Mac", encoderConfiguration: .highQuality, loomConfiguration: .default ) hostService.delegate = self // Configure trust provider for connection approval hostService.trustProvider = myTrustProvider // Enable features hostService.sharedClipboardEnabled = true hostService.lightsOutEnabled = true // Screen curtain while streaming hostService.muteLocalAudioWhileStreaming = true } func start() async throws { try await hostService.start() // Host is now advertising via _mirage._tcp Bonjour } func stop() async { await hostService.stop() } // MARK: - MirageHostDelegate func hostService( _ service: MirageHostService, shouldAcceptConnectionFrom deviceInfo: LoomPeerDeviceInfo, origin: MirageHostConnectionOrigin, completion: @escaping @Sendable (Bool) -> Void ) { // Approve or reject incoming connections completion(true) } func hostService(_ service: MirageHostService, didConnectClient client: MirageConnectedClient) { print("Client connected: \(client.name)") } func hostService(_ service: MirageHostService, didDisconnectClient client: MirageConnectedClient) { print("Client disconnected: \(client.name)") } func hostService( _ service: MirageHostService, didReceiveInputEvent event: MirageInputEvent, forWindow window: MirageWindow, fromClient client: MirageConnectedClient ) { // Handle input events from clients } func hostService(_ service: MirageHostService, sessionStateChanged state: LoomSessionAvailability) { // Handle lock/unlock/sleep state changes } } ``` -------------------------------- ### Initialize and Connect Client Service (iOS/macOS/visionOS) Source: https://github.com/ethanlipnik/miragekit/blob/main/README.md Initialize the MirageClientService and connect to a discovered host. Request the list of available windows after connecting. ```swift import MirageKitClient @MainActor final class ClientController: MirageClientDelegate { let clientService = MirageClientService() init() { clientService.delegate = self } func connect(to host: LoomPeer) async throws { try await clientService.connect(to: host) try await clientService.requestWindowList() } } ``` -------------------------------- ### Initialize and Configure MirageClientService Source: https://context7.com/ethanlipnik/miragekit/llms.txt Initializes the MirageClientService with a device name and session store. Configures iCloud auto-trust and audio settings. Use this to set up the client for discovery and streaming. ```swift import MirageKitClient @MainActor final class ClientController: MirageClientDelegate { let clientService: MirageClientService private var discoveryTask: Task? init() { clientService = MirageClientService( deviceName: "My iPad", sessionStore: MirageClientSessionStore() ) clientService.delegate = self // Configure for iCloud-based auto-trust clientService.iCloudUserID = "user-record-id" // Audio configuration clientService.audioConfiguration = MirageAudioConfiguration( enabled: true, channelLayout: .stereo, quality: .high ) } func startDiscovery() { discoveryTask = Task { for await peer in clientService.loomNode.discover() { print("Discovered host: \(peer.name)") // Store peers for user selection } } } func connect(to host: LoomPeer) async throws { try await clientService.connect(to: host) // Request available windows after connection try await clientService.requestWindowList() // Or request available apps for app-centric streaming try await clientService.requestAppList() } func startDesktopStream(width: Int, height: Int) async throws { try await clientService.startDesktopStream( width: width, height: height, streamMode: .unified, // or .secondary for external display cursorPresentation: .simulatedCursor ) } func startAppStream(bundleIdentifier: String) async throws { try await clientService.startAppStream( bundleIdentifier: bundleIdentifier, width: 1920, height: 1080 ) } func disconnect() async { await clientService.disconnect() } // MARK: - MirageClientDelegate func clientService(_ service: MirageClientService, didUpdateWindowList windows: [MirageWindow]) { print("Windows available: \(windows.count)") } func clientService(_ service: MirageClientService, didDisconnectFromHost reason: String) { print("Disconnected: \(reason)") } func clientService(_ service: MirageClientService, didEncounterError error: Error) { print("Error: \(error.localizedDescription)") } func clientService( _ service: MirageClientService, hostSessionStateChanged state: LoomSessionAvailability, requiresUserIdentifier: Bool ) { // Handle host lock state - show unlock UI if needed } } ``` -------------------------------- ### Build MirageKit Agent Source: https://github.com/ethanlipnik/miragekit/blob/main/AGENTS.md Command to build the MirageKit package. Ensure you are in the project root. ```bash swift build --package-path MirageKit ``` -------------------------------- ### Configure Bonjour Services in Info.plist Source: https://github.com/ethanlipnik/miragekit/blob/main/README.md Add these keys to your app target's Info.plist to enable Bonjour discovery and advertising for MirageKit. Without them, NWBrowser will fail with an error. ```xml NSBonjourServices _mirage._tcp NSLocalNetworkUsageDescription This app uses the local network to discover and connect to nearby devices running Mirage. ``` -------------------------------- ### Build and Test MirageKit Source: https://github.com/ethanlipnik/miragekit/blob/main/README.md Standard commands for building the Swift package and running tests. For host-integration-sensitive changes, a separate xcodebuild command is provided. ```bash swift build --package-path . swift test --package-path . ``` ```bash xcodebuild -project ../Mirage.xcodeproj -scheme 'Mirage Host' -configuration Debug -destination 'platform=macOS' build ``` -------------------------------- ### Configure Audio Streaming (Swift) Source: https://context7.com/ethanlipnik/miragekit/llms.txt Set up audio streaming configuration on the client service, specifying whether audio is enabled, the channel layout, and the desired quality. The audio playback controller can then be accessed to adjust volume. ```swift import MirageKitClient // Configure audio clientService.audioConfiguration = MirageAudioConfiguration( enabled: true, channelLayout: .stereo, // .mono, .stereo, .surround51 quality: .high // .low, .high, .lossless ) // Access audio playback controller let audioController = clientService.audioPlaybackController // Adjust volume audioController.volume = 0.8 // Check audio state print("Audio streaming: \(clientService.audioRegisteredStreamID != nil)") ``` -------------------------------- ### Verify ColorSync Service Stability Source: https://github.com/ethanlipnik/miragekit/blob/main/If-Your-Computer-Feels-Stuttery.md Use these commands to confirm that the colorsyncd and colorsync.displayservices processes have settled down and that the number of Mirage profiles remains low after applying the fix. ```bash top -l 2 -o cpu -n 10 -stats pid,command,cpu,mem,time ``` ```bash ls /Library/ColorSync/Profiles/Displays | grep -c 'Mirage Shared Display' ``` -------------------------------- ### Test MirageKit Agent Source: https://github.com/ethanlipnik/miragekit/blob/main/AGENTS.md Command to run tests for the MirageKit package. Ensure you are in the project root. ```bash swift test --package-path MirageKit ``` -------------------------------- ### Backup and Reset ColorSync Profiles and Services Source: https://github.com/ethanlipnik/miragekit/blob/main/If-Your-Computer-Feels-Stuttery.md Run this command block in Terminal to move Mirage display profiles to a backup folder, reset the ColorSync device cache, and restart ColorSync services. This is most relevant for systems that have created new virtual display identities per session. ```bash ts=$(date +%Y%m%d-%H%M%S) # System-level display profiles (requires sudo) SYS_SRC="/Library/ColorSync/Profiles/Displays" SYS_DST="/Library/ColorSync/Profiles/MirageBackup-$ts" sudo mkdir -p "$SYS_DST" sudo find "$SYS_SRC" -maxdepth 1 -type f -name 'Mirage Shared Display*' -exec mv -n {} "$SYS_DST/" \; # User-level profiles (no sudo) USER_SRC="$HOME/Library/ColorSync/Profiles" USER_DST="$HOME/Library/ColorSync/Profiles/MirageBackup-$ts" mkdir -p "$USER_DST" find "$USER_SRC" -maxdepth 1 -type f -name 'Mirage*' -exec mv -n {} "$USER_DST/" \; # ColorSync device cache reset (requires sudo) CACHE_DST="/Library/Caches/ColorSync/Backup-$ts" sudo mkdir -p "$CACHE_DST" sudo mv /Library/Caches/ColorSync/com.apple.colorsync.devices "$CACHE_DST/" 2>/dev/null || true sudo mv /Library/Caches/ColorSync/Profiles "$CACHE_DST/" 2>/dev/null || true # Restart ColorSync services sudo killall colorsyncd colorsync.displayservices ``` -------------------------------- ### MirageStreamContentView Integration Source: https://context7.com/ethanlipnik/miragekit/llms.txt Integrates input handling, focus management, and resize coordination for desktop streaming views. Use when setting up the main content view for a desktop stream session. ```swift import MirageKitClient import SwiftUI struct DesktopStreamView: View { let sessionStore: MirageClientSessionStore let clientService: MirageClientService @State private var session: MirageStreamSessionState? var body: some View { Group { if let session { MirageStreamContentView( session: session, sessionStore: sessionStore, clientService: clientService, isDesktopStream: true, desktopStreamMode: .unified, desktopCursorPresentation: .simulatedCursor, onExitDesktopStream: { Task { await clientService.stopDesktopStream() } }, directTouchInputMode: .normal, pencilGestureConfiguration: .default, onDictationStateChanged: { isActive in print("Dictation: \(isActive)") }, keyboardAvoidanceEnabled: true ) } else { ProgressView("Connecting...") } } .onAppear { session = sessionStore.activeSessions.first } } } ``` -------------------------------- ### Enable Shared Clipboard (Swift) Source: https://context7.com/ethanlipnik/miragekit/llms.txt Enable clipboard synchronization between the host and client. On the host, set `sharedClipboardEnabled` to true. On the client, enable `clientClipboardSharingEnabled` and optionally `clientClipboardAutoSync` for continuous synchronization. ```swift import MirageKitHost import MirageKitClient // Host-side: enable shared clipboard hostService.sharedClipboardEnabled = true // Client-side: configure clipboard sharing clientService.clientClipboardSharingEnabled = true clientService.clientClipboardAutoSync = true // Continuous sync // Manual clipboard sync (iOS) let synced = await clientService.syncLocalClipboardToHost() ``` -------------------------------- ### Build Mirage Xcode Project Source: https://github.com/ethanlipnik/miragekit/blob/main/AGENTS.md Command to build the Mirage Xcode project for host-integration-sensitive changes. This command targets the macOS platform in Debug configuration. ```bash xcodebuild -project Mirage.xcodeproj -scheme 'Mirage Host' -configuration Debug -destination 'platform=macOS' build ``` -------------------------------- ### Run Network Quality Test (Swift) Source: https://context7.com/ethanlipnik/miragekit/llms.txt Execute a network quality test to determine the optimal bitrate for streaming. The results provide the safe bitrate, round-trip time (RTT), and packet loss percentage. ```swift import MirageKitClient // Run quality test after connecting let summary = try await clientService.runQualityTest() print("Safe bitrate: \(summary.safeBitrate) bps") print("RTT: \(summary.rtt)ms") print("Packet loss: \(summary.packetLoss)%") // Use results to configure stream let bitrate = min(summary.safeBitrate, 100_000_000) let overrides = MirageEncoderOverrides(bitrate: bitrate) ``` -------------------------------- ### Inject Remote Input Events (Swift) Source: https://context7.com/ethanlipnik/miragekit/llms.txt Use the host service's input controller to inject mouse, keyboard, and scroll events into a target window. System actions like Mission Control can also be triggered. ```swift import MirageKitHost // Access via host service let inputController = hostService.inputController // Inject mouse events inputController.injectMouseEvent( event: mouseEvent, window: targetWindow, streamBounds: CGRect(x: 0, y: 0, width: 1920, height: 1080) ) // Inject keyboard events inputController.injectKeyEvent(keyEvent) // Inject scroll events inputController.injectScrollEvent( scrollEvent, window: targetWindow, streamBounds: streamBounds ) // System actions inputController.performSystemAction(.missionControl) inputController.performSystemAction(.showDesktop) inputController.performSystemAction(.launchpad) ``` -------------------------------- ### MirageEncoderConfiguration Presets and Customization Source: https://context7.com/ethanlipnik/miragekit/llms.txt Defines configurations for video encoding, offering presets like 'highQuality' and 'balanced', as well as custom settings with options for codec, frame rate, bitrate, and color depth. Use to tailor video stream quality and performance. ```swift import MirageKit // Use high-quality preset for local network let highQuality = MirageEncoderConfiguration.highQuality // targetFrameRate: 120, bitrate: 130 Mbps // Use balanced preset for lower bandwidth let balanced = MirageEncoderConfiguration.balanced // targetFrameRate: 120, bitrate: 100 Mbps // Custom configuration let custom = MirageEncoderConfiguration( codec: .hevc, targetFrameRate: 60, keyFrameInterval: 1800, colorDepth: .pro, // 10-bit Display P3 scaleFactor: 2.0, captureQueueDepth: nil, bitrate: 80_000_000 ) // Override specific settings let modified = custom.withOverrides( keyFrameInterval: 3600, colorDepth: .standard, // 8-bit sRGB bitrate: 50_000_000 ) // Stream color depths: // .standard - 8-bit sRGB (NV12 pixel format) // .pro - 10-bit Display P3 (P010 pixel format) // .ultra - 10-bit Display P3 with 4:4:4 chroma (when hardware supports) ``` -------------------------------- ### Environment Variables for MirageKit Source: https://context7.com/ethanlipnik/miragekit/llms.txt Environment variables to control MirageKit behavior. `MIRAGE_AWDL_EXPERIMENT` can enable AWDL transport stabilization, and `MIRAGE_DISABLE_LIGHTS_OUT` can disable the screen curtain feature. ```bash # Enable AWDL transport stabilization experiment export MIRAGE_AWDL_EXPERIMENT=1 # Disable Lights Out (screen curtain) feature export MIRAGE_DISABLE_LIGHTS_OUT=1 ``` -------------------------------- ### Add MirageKit as Swift Package Manager Dependency Source: https://github.com/ethanlipnik/miragekit/blob/main/README.md Add MirageKit as a dependency in your Package.swift file to include it in your project. ```swift // Package.swift .package(url: "https://github.com/EthanLipnik/MirageKit.git", from: "0.0.1"), ``` -------------------------------- ### Create SwiftUI Stream View with MirageStreamViewRepresentable Source: https://context7.com/ethanlipnik/miragekit/llms.txt Integrates MirageKit's stream rendering into a SwiftUI view. Handles input events and drawable metrics changes. Requires stream ID and MirageClientService instance. ```swift import MirageKitClient import SwiftUI struct StreamView: View { let streamID: StreamID let clientService: MirageClientService var body: some View { MirageStreamViewRepresentable( streamID: streamID, onInputEvent: { event in // Forward input to host clientService.sendInputFireAndForget(event, forStream: streamID) }, onDrawableMetricsChanged: { metrics in // Update host capture resolution based on client display print("Drawable size: \(metrics.pixelSize)") }, cursorStore: clientService.cursorStore, cursorPositionStore: clientService.cursorPositionStore, syntheticCursorEnabled: true, presentationTier: .activeLive ) } } ``` -------------------------------- ### SwiftUI Stream Content View with MirageStreamContentView Source: https://github.com/ethanlipnik/miragekit/blob/main/README.md Utilize MirageStreamContentView for a higher-level SwiftUI integration. This view manages input, focus, and resize logic by connecting to a MirageClientSessionStore and MirageClientService. ```swift let sessionStore = MirageClientSessionStore() let clientService = MirageClientService(sessionStore: sessionStore) MirageStreamContentView( session: session, // Assuming 'session' is defined elsewhere sessionStore: sessionStore, clientService: clientService, isDesktopStream: false ) ``` -------------------------------- ### SwiftUI Stream View with MirageStreamViewRepresentable Source: https://github.com/ethanlipnik/miragekit/blob/main/README.md Use MirageStreamViewRepresentable to display video frames from a stream in a SwiftUI view. It handles frame presentation and allows forwarding input events. ```swift import MirageKitClient import SwiftUI struct StreamView: View { let streamID: StreamID var body: some View { MirageStreamViewRepresentable( streamID: streamID, onInputEvent: { event in // Forward event to MirageClientService }, onDrawableMetricsChanged: { metrics in // Use to request updated capture resolution } ) } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.