# BeamScribe: MPC to Network.framework Transition Plan ## Overview Transition from MultipeerConnectivity to Network.framework while preserving all existing functionality: live transcription broadcast, late-joiner history sync, alerts, and multi-guest support. --- ## Phase 1: Create P2PConnectionManager (Network.framework Core) ### 1.1 Define the Protocol Interface Create a protocol that mirrors what `MultipeerManager` currently provides to the UI: ```swift protocol P2PConnectionDelegate: AnyObject { func didDiscoverHost(_ host: DiscoveredHost) func didLoseHost(_ host: DiscoveredHost) func didConnectGuest(_ guest: ConnectedPeer) func didDisconnectGuest(_ guest: ConnectedPeer) func didReceiveData(_ data: Data, from peer: ConnectedPeer) func connectionStateChanged(_ state: P2PConnectionState) } ``` ### 1.2 Host Side: NWListener Replace `MCNearbyServiceAdvertiser` with `NWListener`: ```swift // Key configuration let parameters = NWParameters.tcp parameters.includePeerToPeer = true // Enables AWDL parameters.serviceClass = .responsiveData // Low-latency priority // Advertise with service type let listener = try NWListener(using: parameters) listener.service = NWListener.Service( name: eventName, // Your event name (currently in discoveryInfo) type: "_beamscribe._tcp" ) ``` **Connection Handling:** - Store accepted connections in `[UUID: NWConnection]` dictionary - Implement same 4-second "traffic gate" stabilization logic - Track unstable connections (disconnect within 5 seconds) ### 1.3 Guest Side: NWBrowser + NWConnection Replace `MCNearbyServiceBrowser` with `NWBrowser`: ```swift let parameters = NWParameters.tcp parameters.includePeerToPeer = true let browser = NWBrowser(for: .bonjour(type: "_beamscribe._tcp", domain: nil), using: parameters) ``` **Discovery Results:** - `NWBrowser.Result` includes the service name (your event name) - Create `NWConnection` to connect to discovered host - Implement retry logic (1s, 2s, 4s backoff - same as current) --- ## Phase 2: BLE Fast-Discovery Layer (CoreBluetooth) ### 2.1 Why BLE? Standard Bonjour discovery over AWDL can take 2-8 seconds due to channel hopping. BLE advertisement is near-instant and "wakes" the AWDL interface. ### 2.2 BLEDiscoveryManager - Host (Peripheral) ```swift let serviceUUID = CBUUID(string: "YOUR-BEAMSCRIBE-UUID") // Advertise when hosting peripheralManager.startAdvertising([ CBAdvertisementDataServiceUUIDsKey: [serviceUUID], CBAdvertisementDataLocalNameKey: eventName.prefix(8) // BLE has 28-byte limit ]) ``` ### 2.3 BLEDiscoveryManager - Guest (Central) ```swift // Scan for BeamScribe hosts centralManager.scanForPeripherals(withServices: [serviceUUID]) // On discovery, trigger Network.framework browser func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, ...) { delegate?.bleDidDiscoverHost(name: peripheral.name) // Start NWBrowser immediately - AWDL is now primed } ``` ### 2.4 BLE Lifecycle - Start BLE advertising when `startHosting()` called - Start BLE scanning when `startBrowsing()` called - Stop BLE once TCP connection established (saves battery) - Resume BLE if connection lost (for reconnection) --- ## Phase 3: Data Transmission Layer ### 3.1 Framing Protocol Network.framework uses raw TCP streams. Implement length-prefixed framing: ```swift // Sending func send(_ packet: TranscriptPacket, to connection: NWConnection) { let data = try JSONEncoder().encode(packet) var length = UInt32(data.count).bigEndian let header = Data(bytes: &length, count: 4) connection.send(content: header + data, completion: .contentProcessed { ... }) } // Receiving func receiveNextPacket(on connection: NWConnection) { // Read 4-byte header first, then read that many bytes for payload } ``` ### 3.2 Broadcast to All Guests (Host) Replace `MCSession.send(_:toPeers:with:)`: ```swift func broadcastPacket(_ packet: TranscriptPacket) { let data = encode(packet) for (_, connection) in stableConnections { connection.send(content: data, completion: ...) } } ``` ### 3.3 Packet Types (Keep Existing) Your current `TranscriptPacket` model works unchanged: - `.fullHistory` - Late-joiner sync - `.liveChunk` - Real-time transcription (partial/final) - `.alert` - Host disconnected, battery low, session resumed --- ## Phase 4: Integration with Existing Code ### 4.1 File Changes Summary | Current File | Changes | |--------------|---------| | `MultipeerManager.swift` | Deprecate, keep as fallback initially | | `P2PConnectionManager.swift` | NEW - Main networking logic | | `BLEDiscoveryManager.swift` | NEW - CoreBluetooth layer | | `NetworkFraming.swift` | NEW - TCP framing utilities | | `SessionState.swift` | Update peer tracking types | | `ContentView.swift` | Swap manager reference | | `GuestBrowserView.swift` | Use new discovery delegate | | `Info.plist` | Add BLE background modes | ### 4.2 Info.plist Additions ```xml UIBackgroundModes bluetooth-central bluetooth-peripheral NSBluetoothAlwaysUsageDescription BeamScribe uses Bluetooth to quickly discover nearby sessions. ``` ### 4.3 Fallback Strategy Keep `MultipeerManager` available initially: ```swift // In SessionState or AppConfig var useNetworkFramework: Bool = true var connectionManager: any P2PConnectionDelegate { useNetworkFramework ? p2pManager : legacyMultipeerManager } ``` --- ## Phase 5: Testing & Verification ### 5.1 Terminal Checks ```bash # Verify AWDL activates during connection ifconfig awdl0 # Check for active peer-to-peer interface netstat -rn | grep awdl ``` ### 5.2 Latency Testing ```swift // Add to packet for round-trip measurement struct TranscriptPacket { // existing fields... var sentTimestamp: TimeInterval? } ``` ### 5.3 Test Scenarios - [ ] Host starts, 1 guest joins - [ ] Host starts, 7 guests join simultaneously - [ ] Guest joins late, receives full history - [ ] Host disconnects, guests receive alert - [ ] App backgrounded, BLE keeps discovery alive - [ ] Same Wi-Fi network (should prefer infrastructure) - [ ] Different Wi-Fi / no Wi-Fi (should use AWDL) --- ## Implementation Order 1. **P2PConnectionManager** - NWListener + NWBrowser (no BLE yet) 2. **NetworkFraming** - Length-prefixed TCP framing 3. **Integration** - Wire up to ContentView/GuestBrowserView 4. **Testing** - Verify feature parity with MPC 5. **BLEDiscoveryManager** - Add fast-discovery layer 6. **Optimization** - Infrastructure vs AWDL preference logic 7. **Cleanup** - Remove MultipeerManager fallback --- ## Estimated New Files ``` BeamScribe/ ├── Managers/ │ ├── MultipeerManager.swift (existing - deprecate later) │ ├── P2PConnectionManager.swift (NEW - ~400 lines) │ ├── BLEDiscoveryManager.swift (NEW - ~150 lines) │ └── NetworkFraming.swift (NEW - ~80 lines) ├── Models/ │ ├── DiscoveredHost.swift (NEW - ~20 lines) │ └── ConnectedPeer.swift (NEW - ~20 lines) ``` --- ## Rollback Plan If issues arise: ```bash git reset --hard backup-before-networkframework ```