In the delegate method below, distance is of type Float:
func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObject]) {
		guard let object = nearbyObjects.first else { return }
guard let distance = object.distance else { return }
print("distance is of type Float but I need to convert to meters: ", distance)
}
How do I convert distance into meters so that I can find out exactly how far the peers are from one another?
Post
Replies
Boosts
Views
Activity
Because of the 8 peer limit I'm using NWListener, NWBrowser, NWConnection, and Bonjour for up to 20 peer-to-peer concurrent connections.
I followed this answer - https://developer.apple.com/forums/thread/652180 and this answer - https://developer.apple.com/forums/thread/661148 which are both from Apple engineers.
The first one said to create multiple concurrent NISessions:
All NISessions are peer-to-peer and as a result, creating multiple NISession objects is necessary to have multiple concurrent sessions. One approach is to create a dictionary between an identifier for the peer (i.e. a user identifier provided by your app MyAppUserID) and the NISession objects while also keeping track of the NIDiscoveryToken for each peer identifier: var sessions = [MyAppUserID: NISession]()
var peerTokensMapping = [NIDiscoveryToken: MyAppUserID]() And the second answer said to perform interactions with multiple iPhones:
Create an NISession for each peer you would like to interact with. For example, if you are interacting with two peers, create 2 * NISession objects. Each NISession will have a unique NIDiscoveryToken associated with it. Share discovery token #1 with peer #1, and share discovery token #2 with peer #2. When you receive discovery tokens from peers #1 and #2, create 2 * NINearbyPeerConfiguration objects and use them to run sessions #1 and #2, respectively. The problem is when sending out a NIDiscoveryToken via NWConnection, I can't find a way to link to the NISession from the sent out data to the token that is received from the incoming data after I initialize a NINearbyPeerConfiguration object:
eg.
User object which is sent and received when other devices are discovered
class User: NSObject, NSSecureCoding {
		var uid: String?
		var peerToken: NIDiscoveryToken? = nil
		init(uid: String, peerToken: NIDiscoveryToken) {...}
		// ... encoder for uid and peerToken
		// ... decoder for uid and peerToken
}
Send current user's NIDiscoveryToken data via NWBrowser and NWConnection and save it to the
peerTokensMapping dictionary and save the session to the sessionsArr
let currentUserId = "qwerty"
var sessionsArr = [NISession]()
var sessions = [String: NISession]()
var peerTokensMapping = [NIDiscoveryToken: String]()
func sendDataWhenNewDeviceIsDiscovered() {
		let session = NISession()
		session.delegate = self
		guard let myToken = session.discoveryToken else { return }
		let user = User(uid: currentUserId, peerToken: myToken)
		guard let outgoingData = try? NSKeyedArchiver.archivedData(withRootObject: user,
																														 requiringSecureCoding: true)
		else { return }
		let message = NWProtocolWebSocket.Metadata(opcode: .text)
		let context = NWConnection.ContentContext(identifier: "send", metadata: [message])
		connection.send(content: outgoingData, contentContext: context, isComplete: true, completion: .contentProcessed({ [weak self](error) in
		if let error = error { return }
				self?.sessionsArr.append(session)
				self?.peerTokensMapping[myToken] = self!.currentUserId
		print("Successfully Sent")
		}))
}
Receive other user's NIDiscoveryToken data via NWListener and NWConnection.
connection.receive(minimumIncompleteLength: 1, maximumLength: 65535) {
		[weak self](data, context, isComplete, error) in
		if let err = error { return }
		if let data = data, !data.isEmpty {
				self?.decodeReceived(data)
		}
}
func decodeReceived(_ data: Data) {
		guard let incomingData = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? User
		else { return }
		guard let uid = incomingData.uid, let peerToken = incomingData.peerToken
		else { return }
		let config = NINearbyPeerConfiguration(peerToken: peerToken)
		/* not sure what to do here to get the session that was created when the data was sent out */
		for (key,_) in peerTokensMapping {
				if key.??? == peerToken.??? {
						session.run(config)
						self.sessions[currentUserId] = session
						break
				}
		}
		/* or try this but this is the other user's peerToken so this will never work */
		for session in self.sessionsArr {
				if session.discoveryToken ?? "" == peerToken {
						session.run(config)
						self.sessions[currentUserId] = session
						break
				}
		}
}
Once the NINearbyPeerConfiguration is initialized how do I connect the incoming peerToken with the correct one that was sent out above that is currently inside the peerTokensMapping dict or the sessionsArr so that I can
get the session and call session.run(config)
I have the same exact problem as this question - https://developer.apple.com/forums/thread/113809.
device-1 browses, discovers, and sends a message to device-2. The connection is made. I hold a copy to the outgoing connection inside an array.
device-2 receives the message and I hold a copy of the incoming connection inside an array.
The same thing happens in reverse with device-2 to device-1 (peer-to-peer) setup.
When either device goes to the background, I iterate through the array, .cancel the connection, then remove it from the array. The problem is when the connection is no longer connected, the opposite device fires browser.browseResultsChangedHandler but it never fires connection.stateUpdateHandler, it will only fire if it itself shuts the connection down.
device-1:
var connections = [NWConnection]()
@objc func backgroundNotification() {
		 connections.forEach({ $0.cancel() })
connections.removeAll()
		 // I've also tried cancelling and setting both the browser and listener to nil
}
device-1 is no longer connected, device-2 -only the browseResultsChangedHandler fires
browser.browseResultsChangedHandler = { [weak self](results, changes) in
		for change in changes {
				switch change {
						// ...
						case .removed(let browseResult):
								if case .service(let name, let type, let domain, _) = browseResult.endpoint {
										// * only this runs *
								}
						default:break
				}
		}
}
var connections = [NWConnection]()
connection.stateUpdateHandler = { [weak self](nwConnectionState) in
	// *.cancelled* and *.failed* never run
switch nwConnectionState {
// ...
case .cancelled:
			connection.cancel()
		// ... loop the array and remove the connection
case .failed(let error):
			connection.cancel()
		// ... loop the array and remove the connection
default:break
}
}
The odd thing is if device-2 goes to the background (same step as device-1), then connection.stateUpdateHandler does fire.
Just to be clear when sending messages everything works fine on both devices and in both the browser and listener handlers.
I'm using AVPlayer and sometimes the player randomly pauses. I'm observing \.timeControlStatus but the only response I get .paused with no info as to why it's paused.
I'm also observing \.isPlaybackLikelyToKeepUp, \.isPlaybackBufferEmpty, and \.isPlaybackBufferFull but nothing fires for those. However using Notification.Name.AVPlayerItemPlaybackStalled I do get a print statement that says "stalled".
I have no idea what to do because the player is justing sitting there and I get no information as to what the problem.
How can I find out the exact reason why the player is stalled?
How do I resume automatic play after the player is paused?
code is in attachment
AVPlayer Observers and Notifications - https://developer.apple.com/forums/content/attachment/98542fe1-0678-4922-806a-e8b9ae09ceed