swiftmacosmultipeer-connectivity

How can I invite a peer to a session using a different name from the one that I found the peer with?


I am using the Multipeer Connectivity Framework on macOS, and I am trying to implement the functionality of connecting to other peers. I used a MCNearbyServiceBrowser and displayed the found peers in an NSTableView. I also have a NSTextField for people to enter their display name, which will be the display name of their MCPeerID.

The workflow is as follows: The user enter a display name, selects a peer from the NSTableView, and press the connect button.

enter image description here

This means that I don't have an MCPeerID until the connect button is pressed, because before that time the textfield text could still change. However, initialising a MCNearbyServiceBrowser requires an MCPeerID, so I thought I could use a dummy peer ID for the browser, then create the real one when the connect button is pressed, like this:

let dummyPeerID = MCPeerID(displayName: "Unnamed")
override func viewDidLoad() {
    browser = MCNearbyServiceBrowser(peer: dummyPeerID, serviceType: "some identifier")
    ...
}

@IBAction func connect(_ sender: NSButton) {
    let peerID = MCPeerID(displayName: displayNameTextField.stringValue)
    session = MCSession(peer: peerID)
    session.delegate = self
    activityIndicator.isHidden = false
    activityIndicator.startAnimation(nil)
    // selectedTeacher is an RxSwift.Variable<MCPeerID?> that is bound to the selected model object of the table view
    browser.invitePeer(selectedTeacher.value!, to: session, withContext: nil, timeout: 10)
}

When I run this code, I saw that session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) is called with a state of .notConnected, and this is printed in the console:

Wrong connection data. Participant ID from remote connection data = 7008A6B3, local participant ID = 4F1F9C8D.

I suppose that it means I can't use different MCPeerIDs for the browser and the session. If I change this line:

session = MCSession(peer: peerID)

to:

session = MCSession(peer: dummyPeerID)

Then it is connected to the session correctly.


What can I do in this situation, where I don't know the display name of the local peer when browsing for other peers? (Let's assume we can't change the UI design)


Solution

  • I can think of two solutions: using data contexts or using a second browser

    Using data contexts

    Use your dummy id but don't rely on its displayName property. Instead pass your real display name via the context parameter of invitePeer(_ peerID: MCPeerID, to session: MCSession, withContext context: Data?, timeout: TimeInterval)

    @IBAction func connect(_ sender: NSButton) {
        session = MCSession(peer: dummyPeerID)
        session.delegate = self
        activityIndicator.isHidden = false
        activityIndicator.startAnimation(nil)
    
        browser.invitePeer(
          selectedTeacher.value!,
          to: session,
          withContext: displayNameTextField.stringValue.data(using: .utf8)!,
          timeout: 10
        )
    }
    

    Using a second browser

    Create a new MCPeerID and create a second browser with your new MCPeerID. Wait until the selectedTeacher is discovered again using your second browser and then use that browser with the new ID to invite the selectedTeacher.

    var dummyBrowser: InvitingBrowser?
    @IBAction func connect(_ sender: NSButton) {
        let peerID = MCPeerID(displayName: displayNameTextField.stringValue)
        session = MCSession(peer: peerID)
        session.delegate = self
        activityIndicator.isHidden = false
        activityIndicator.startAnimation(nil)
        // selectedTeacher is an RxSwift.Variable<MCPeerID?> that is bound to the selected model object of the table view
        dummyBrowser = InvitingBrowser(
          session: session,
          serviceType: mcService,
          remote: selectedTeacher.value!
        )
    }
    
    class InvitingBrowser: NSObject, MCNearbyServiceBrowserDelegate {
        let browser: MCNearbyServiceBrowser
        var remote: MCPeerID
        let session: MCSession
    
        init(session: MCSession, serviceType: String, remote: MCPeerID) {
            browser = MCNearbyServiceBrowser(peer: session.myPeerID, serviceType: serviceType)
            self.remote = remote
            self.session = session
            super.init()
            browser.delegate = self
            browser.startBrowsingForPeers()
        }
    
        func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
            if peerID == remote {
                browser.invitePeer(peerID, to: session, withContext: nil, timeout: 30)
                browser.stopBrowsingForPeers()
            }
        }
    
        func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {}
    }