我正在尝试使用MPC开发多用户AR游戏。连接,发送和接收数据工作正常。但是,为了发送实时播放器位置信息,我想使用流来避免延迟问题。我可以启动流(我认为),但是当我尝试将数据写入输出流时,它只能工作一次。之后,outputstream.hasSpaceAvailable始终为false。我查看了整个网络,但找不到一个单独的示例,其中swift 3或4中使用了流。在我的项目的精简代码下面。希望有人能告诉我我做错了什么。
import UIKit
import SceneKit
import ARKit
import MultipeerConnectivity
class ViewController: UIViewController, ARSCNViewDelegate, MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate, MCSessionDelegate, StreamDelegate {
@IBOutlet var sceneView: ARSCNView!
let MultiPeerType = "artoytrain"
let myPeerId = MCPeerID(displayName: UIDevice.current.name)
var streamTargetPeer: MCPeerID?
var serviceAdvertiser : MCNearbyServiceAdvertiser!
var serviceBrowser : MCNearbyServiceBrowser!
var outputStream: OutputStream?
var counter = 0
var streaming = false
lazy var session : MCSession =
{
let session = MCSession(peer: self.myPeerId, securityIdentity: nil, encryptionPreference: MCEncryptionPreference.none)
session.delegate = self
return session
}()
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
startMPC()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// Run the view's session
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
if streaming {
var float1 = Float(counter)
let data = Data(buffer: UnsafeBufferPointer(start: &float1, count: 1))
counter += 1
guard let outputStream = outputStream else
{
print("no stream")
return
}
if outputStream.hasSpaceAvailable == true
{
outputStream.write(data.withUnsafeBytes { $0.pointee }, maxLength: 4)
}
else
{
print("no space available")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
}
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted, for example, by presenting an overlay
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking and/or remove existing anchors if consistent tracking is required
}
// Multi Peer Connectivity
//init
func startMPC() {
serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerId, discoveryInfo: nil, serviceType: MultiPeerType)
serviceBrowser = MCNearbyServiceBrowser(peer: myPeerId, serviceType: MultiPeerType)
serviceAdvertiser.delegate = self
serviceAdvertiser.startAdvertisingPeer()
serviceBrowser.delegate = self
serviceBrowser.startBrowsingForPeers()
}
// advertiser
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didNotStartAdvertisingPeer error: Error) {
print("didNotStartAdvertisingPeer: \(error)")
}
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
print("didReceiveInvitationFromPeer \(peerID)")
invitationHandler(true, self.session)
}
// browser
func browser(_ browser: MCNearbyServiceBrowser, didNotStartBrowsingForPeers error: Error) {
print("didNotStartBrowsingForPeers: \(error)")
}
func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
print("foundPeer: \(peerID)")
streamTargetPeer = peerID
browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 10)
}
func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
print("lostPeer: \(peerID)")
}
// session
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
print("peer \(peerID) didChangeState: \(state)")
connectedDevicesChanged(connectedDevices: session.connectedPeers.map{$0.displayName})
}
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
print("didReceiveData: \(data)")
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
print("didReceiveStream",stream,streamName,stream.hasBytesAvailable)
stream.schedule(in: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
stream.delegate = self
stream.open()
}
func stream(_ stream: Stream, handle eventCode: Stream.Event)
{
print("stream entered")
if let inputStream = stream as? InputStream , eventCode == Stream.Event.hasBytesAvailable
{
var bytes = [UInt8](repeating: 0, count:4)
inputStream.read(&bytes, maxLength: 4)
print("input stream",bytes)
}
}
func startStream()
{
print("startstream")
guard let streamTargetPeer = streamTargetPeer, outputStream == nil else
{
return
}
do
{
outputStream = try session.startStream(withName: "stream", toPeer: streamTargetPeer)
outputStream?.schedule(in: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
outputStream?.open()
print("output stream is open")
streaming = true
}
catch
{
print("unable to start stream!! \(error)")
}
}
func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {
print("didStartReceivingResourceWithName")
}
func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {
print("didFinishReceivingResourceWithName")
}
func connectedDevicesChanged(connectedDevices: [String]) {
print("MM Connections: \(connectedDevices)")
if connectedDevices.count > 0 {
print("connected, so start streaming")
startStream()
}
}
}