private void UpdateReceivers() { var confirmPacketInfos = new List <ConfirmPacketInfo>(); var senderPacketInfos = new Dictionary <int, SenderPacketInfo>(); try { SenderPacketClassifier.Classify(udpSocket, receivers.Values, confirmPacketInfos, senderPacketInfos); } catch (UdpSocketException e) { TextToaster.Toast($"Error from SenderPacketClassifier.Classify(): {e.Message}"); } foreach (var confirmPacketInfo in confirmPacketInfos) { int receiverId = confirmPacketInfo.ConfirmPacket.receiverId; print($"confirmPacketInfo - 1: receiver: {receiverId}"); // Ignore if there is already a receiver with the receiver ID. if (receivers.ContainsKey(receiverId)) { continue; } print($"confirmPacketInfo - 2: receiver: {receiverId}, sender: {confirmPacketInfo.ConfirmPacket.senderId}"); // Receiver and KinectOrigin gets created together. // When destroying any of them, the other of the pair should also be destroyed. var receiver = new Receiver(receiverId, confirmPacketInfo.ConfirmPacket.senderId, confirmPacketInfo.SenderEndPoint); receivers.Add(confirmPacketInfo.ConfirmPacket.receiverId, receiver); var kinectOrigin = sharedSpaceScene.AddKinectNode(receiverId); // Apply transformation of kinectSenderElement if there is a corresponding one. if (controllerScene != null) { var controllerNode = controllerScene.FindNode(receiver.SenderEndPoint); if (controllerNode != null) { kinectOrigin.transform.localPosition = controllerNode.position; kinectOrigin.transform.localRotation = controllerNode.rotation; } } } // Send heartbeat packets to senders. foreach (var receiver in receivers.Values) { receiver.SendHeartBeat(udpSocket); } // Using a copy of remoteSenders through ToList() as this allows removal of elements from remoteSenders. foreach (var senderPacketInfoPair in senderPacketInfos) { // The keys of senderPacketInfos are sender IDs, not receiver IDs like other collections. int senderId = senderPacketInfoPair.Key; // Since senderPacketInfos were built based on receivers, there should be a corresponding receiver. var receiver = receivers.Values.First(x => x.SenderId == senderId); var kinectNode = sharedSpaceScene.GetKinectNode(receiver.ReceiverId); receiver.ReceivePackets(udpSocket, senderPacketInfoPair.Value, kinectNode.KinectRenderer.Material, kinectNode.Speaker.RingBuffer); // Remove receivers that did not receive any packet for too long. if (receiver.IsTimedOut()) { TextToaster.Toast($"Receiver {receiver.ReceiverId} timed out."); receivers.Remove(receiver.ReceiverId); sharedSpaceScene.RemoveKinectNode(receiver.ReceiverId); continue; } if (kinectNode.KinectRenderer.State == PrepareState.Unprepared) { if (receiver.VideoMessages.Count > 0) { foreach (var videoMessage in receiver.VideoMessages.Values) { CoroutineRunner.RunWithTotalTimeOut(kinectNode.KinectRenderer.Prepare(videoMessage)); break; } } } else if (kinectNode.KinectRenderer.State == PrepareState.Preparing) { kinectNode.SetProgressText(receiver.SenderEndPoint, kinectNode.kinectRenderer.Progress); kinectNode.ProgressTextVisibility = true; } else if (kinectNode.KinectRenderer.State == PrepareState.Prepared) { kinectNode.ProgressTextVisibility = false; } var floorVideoMessage = receiver.VideoMessages.Values.FirstOrDefault(x => x.floor != null); if (floorVideoMessage != null) { kinectNode.UpdateFrame(floorVideoMessage.floor); } receiver.UpdateFrame(udpSocket); } }