示例#1
0
 public void StartRecordingAvatars(Dictionary <RefID, Slot> avatar_roots, string override_filename = null)
 {
     foreach (var item in avatar_roots)
     {
         RefID user_id  = item.Key;
         Slot  rootSlot = item.Value;
         VRIK  comp     = rootSlot.GetComponentInChildren <VRIK>();
         if (comp != null)
         {
             IKSolverVR solver = (IKSolverVR)comp.Solver;
             boness[user_id] = solver.BoneReferences;
             string filename = "";
             if (override_filename != null)
             {
                 filename = saving_folder + "/" + override_filename + "_mocap.bvh";
             }
             else
             {
                 filename = saving_folder + "/" + user_id.ToString() + "_mocap.bvh";
             }
             fileWriters[user_id] = new System.IO.StreamWriter(filename);
             filenames[user_id]   = filename;
             BvhHeaderWrite(fileWriters[user_id], boness[user_id]);
         }
     }
     isRecording = true;
 }
示例#2
0
 public void StartRecording()
 {
     current_users_ids = new List <string>();
     saving_folder     = metagen_comp.dataManager.saving_folder;
     foreach (var item in metagen_comp.userMetaData)
     {
         User         user     = item.Key;
         UserMetadata metadata = item.Value;
         if (!metadata.isRecording || (metagen_comp.LocalUser == user && !metagen_comp.record_local_user))
         {
             continue;
         }
         RefID user_id = user.ReferenceID;
         current_users_ids.Add(user_id.ToString());
         AvatarAudioOutputManager comp = user.Root.Slot.GetComponentInChildren <AvatarAudioOutputManager>();
         AudioOutput audio_output      = comp.AudioOutput.Target;
         audio_outputs[user_id] = audio_output;
         if (audio_outputs[user_id] == null)
         {
             UniLog.Log("OwO: Audio output for user " + user_id.ToString() + " is null!");
         }
         else
         {
             UniLog.Log("Sample rate");
             UniLog.Log(metagen_comp.Engine.AudioSystem.Connector.SampleRate.ToString());
             audio_recorders[user_id] = new AudioRecorder(saving_folder + "/" + user_id.ToString() + "_voice_tmp", metagen_comp.Engine.AudioSystem.BufferSize, 1, metagen_comp.Engine.AudioSystem.SampleRate, 1);
             audio_recorders[user_id].StartWriting();
         }
     }
     isRecording = true;
 }
示例#3
0
 public void StartInteracting()
 {
     foreach (var item in metagen_comp.userMetaData)
     {
         User         user     = item.Key;
         UserMetadata metadata = item.Value;
         if (!(metadata.isRecording || metagen_comp.record_everyone))
         {
             continue;
         }
         UniLog.Log("Starting voice interaction for user " + user.UserName);
         RefID user_id = user.ReferenceID;
         current_users_ids.Add(user_id.ToString());
         AvatarAudioOutputManager comp = user.Root.Slot.GetComponentInChildren <AvatarAudioOutputManager>();
         AudioOutput audio_output      = comp.AudioOutput.Target;
         audio_outputs[user_id] = audio_output;
         isRecording[user_id]   = false;
         if (audio_outputs[user_id] == null)
         {
             UniLog.Log("OwO: Audio output for user " + user_id.ToString() + " is null!");
         }
         else
         {
             UniLog.Log("Sample rate");
             UniLog.Log(metagen_comp.Engine.AudioSystem.Connector.SampleRate.ToString());
         }
     }
     isInteracting = true;
 }
示例#4
0
        public void StartRecording()
        {
            World currentWorld = metagen_comp.World;

            current_users_ids = new List <string>();
            currentWorld.RunSynchronously(() =>
            {
                foreach (var item in metagen_comp.userMetaData)
                {
                    User user             = item.Key;
                    UserMetadata metadata = item.Value;
                    if (!metadata.isRecording || (metagen_comp.LocalUser == user && !metagen_comp.record_local_user))
                    {
                        continue;
                    }
                    RefID user_id = user.ReferenceID;
                    current_users_ids.Add(user_id.ToString());
                    Slot localSlot            = user.Root.HeadSlot.AddLocalSlot("vision recorder camera");
                    FrooxEngine.Camera camera = localSlot.AttachComponent <FrooxEngine.Camera>();
                    camera.GetRenderSettings(camera_resolution);
                    camera.NearClipping.Value = 0.15f;
                    cameras[user_id]          = camera;
                    int fps = 30;
                    visual_recorders[user_id] = new VideoRecorder(Path.Combine(saving_folder, user_id.ToString() + "_vision_tmp.avi"), camera_resolution.x, camera_resolution.y, fps, metagen_comp);
                }
                UniLog.Log("Made visual recorder");
                isRecording = true;
            });
        }
示例#5
0
        void StartWritingFile(RefID user_id)
        {
            Guid g = Guid.NewGuid();

            audio_recorders[user_id] = new AudioRecorder(saving_folder + "/" + user_id.ToString() + "_voice_tmp_" + g.ToString(), metagen_comp.Engine.AudioSystem.BufferSize, 1, metagen_comp.Engine.AudioSystem.SampleRate, 1);
            audio_recorders[user_id].StartWriting();
            isRecording[user_id] = true;
        }
示例#6
0
        void StopWritingFile(RefID user_id)
        {
            isRecording[user_id] = false;
            audio_recorders[user_id].WriteHeader();
            string fileName = audio_recorders[user_id].fileName + ".wav";

            File.Move(fileName, fileName.Replace("voice_tmp", "voice_ready"));
        }
示例#7
0
 public void RegisterUserStreams(string name)
 {
     foreach (var userItem in metagen_comp.userMetaData)
     {
         User         user     = userItem.Key;
         UserMetadata metadata = userItem.Value;
         if (!metadata.isRecording || (metagen_comp.LocalUser == user && !metagen_comp.record_local_user))
         {
             continue;
         }
         RefID user_id = user.ReferenceID;
         RegisterUserStream(user_id, name);
     }
 }
 private void ReadHeadings()
 {
     foreach (var item in pose_readers)
     {
         RefID         refID  = item.Key;
         BinaryReaderX reader = item.Value;
         //send heading bytes to GRPC
         byte[] byteArray = reader.ReadBytes((int)reader.BaseStream.Length);
         Google.Protobuf.ByteString byteString = Google.Protobuf.ByteString.CopyFrom(byteArray, 0, byteArray.Length);
         client.SendHeadingBytes(new Heading {
             RefId = refID.ToString(), Data = byteString
         });
     }
 }
示例#9
0
        public void RegisterUserStream(RefID user_id, string name)
        {
            Tuple <BitBinaryWriterX, BitBinaryReaderX> streams = RegisterStream(user_id.ToString() + "_" + name);
            BitBinaryWriterX bitBinaryWriter = streams.Item1;
            BitBinaryReaderX bitBinaryReader = streams.Item2;

            if (bitBinaryWriter != null)
            {
                output_writers[user_id] = bitBinaryWriter;
            }
            if (bitBinaryReader != null)
            {
                output_readers[user_id] = bitBinaryReader;
            }
        }
 public void InteractPoseStreams(float deltaT)
 {
     if (channel.State != ChannelState.Ready)
     {
         return;
     }
     try
     {
         //UniLog.Log("InteractPoseStreams");
         foreach (var item in pose_writers)
         {
             RefID        refID  = item.Key;
             BinaryWriter writer = item.Value;
             //read heading bytes from GRPC
             //byte[] bs = null;
             ByteString bs1 = client.GetFrameBytes(new RefIDMessage {
                 RefId = refID.ToString()
             }).Data;
             //writer.Write(bs1.ToByteArray());
             //writer.BaseStream.Write(bs1.ToByteArray(),(int) writer.BaseStream.Position, bs1.Length);
             UniLog.Log(writer.BaseStream.Position);
             writer.Write(bs1.ToByteArray());
             UniLog.Log(writer.BaseStream.Position);
             UniLog.Log(bs1.Length);
             writer.BaseStream.Position -= bs1.Length;
             //writer.Write(frame_bs);
         }
         metagen_comp.streamPlayer.PlayStreams();
         metagen_comp.metaRecorder.streamRecorder.RecordStreams(deltaT);
         foreach (var item in pose_readers)
         {
             RefID         refID  = item.Key;
             BinaryReaderX reader = item.Value;
             //send heading bytes to GRPC
             byte[] byteArray = reader.ReadBytes((int)reader.BaseStream.Length);
             Google.Protobuf.ByteString byteString = Google.Protobuf.ByteString.CopyFrom(byteArray, 0, byteArray.Length);
             client.SendFrameBytes(new Frame {
                 RefId = refID.ToString(), Data = byteString
             });
         }
     }
     catch (Exception e)
     {
         UniLog.Log("OwO: " + e.Message);
     }
 }
示例#11
0
 //Record one chunk from the voice audio of each user
 public void RecordAudio()
 {
     //Debug.Log("Recording audio");
     foreach (var item in audio_outputs)
     {
         AudioOutput audio_output = item.Value;
         RefID       user_id      = item.Key;
         if (audio_output != null)
         {
             buffer.EnsureSize <float>(metagen_comp.Engine.AudioSystem.BufferSize, false);
             if (audio_output.Source.Target != null)
             {
                 //AudioSystemConnector.InformOfDSPTime(AudioSettings.dspTime);
                 FrooxEngine.Engine.Current.AudioRead();
                 audio_sources_ready = true;
                 AudioStream <MonoSample> stream = (AudioStream <MonoSample>)audio_output.Source.Target;
                 stream.Read <MonoSample>(buffer.AsMonoBuffer());
                 //if (buffer.Length > stream.MissedSamples)
                 //{
                 //    buffer = buffer.Take(buffer.Length - stream.MissedSamples).ToArray();
                 //buffer[0] = 0f;
                 //buffer[1] = 0f;
                 //buffer[2] = 0f;
                 //buffer[3] = 0f;
                 //Console.WriteLine("[{0}]", string.Join(", ", buffer));
                 for (int i = 0; i < buffer.Length; i++)
                 {
                     buffer[i] = MathX.Clamp(buffer[i], -1, 1);
                 }
                 //UniLog.Log(buffer.Length);
                 audio_recorders[user_id].ConvertAndWrite(buffer);
                 //Task.Run(() => { audio_recorders[user_id].ConvertAndWrite(buffer); });
                 //metagen_comp.StartTask(async () => { audio_recorders[user_id].ConvertAndWrite(buffer); });
                 //}
             }
             else
             {
                 UniLog.Log("Audio Output Source target was null! (hmm should we restart it?). Did it happen coz a user left (in which case we shouldn't restart it), or something else?");
                 //UniLog.Log("Restarting audio recording coz audio output source target was null!");
                 //StopRecording();
                 //StartRecording();
             }
         }
     }
 }
 private void WriteHeadings()
 {
     foreach (var item in pose_writers)
     {
         RefID        refID  = item.Key;
         BinaryWriter writer = item.Value;
         //read heading bytes from GRPC
         ByteString bs1 = client.GetHeadingBytes(new RefIDMessage {
             RefId = refID.ToString()
         }).Data;
         UniLog.Log(bs1.Length);
         //byte[] bs = new byte[bs1.Length];
         //bs1.CopyTo(bs, 0);
         //writer.BaseStream.Write(bs1.ToByteArray(),(int) writer.BaseStream.Position, bs1.Length);
         writer.Write(bs1.ToByteArray());
         writer.BaseStream.Position -= bs1.Length;
     }
 }
 private void StartInteractingInternal()
 {
     try
     {
         UniLog.Log("Start pose stream interaction");
         channel = new Channel("127.0.0.1:" + (40052).ToString(), ChannelCredentials.Insecure);
         UniLog.Log("Started grpc channel");
         client = new PoseInteraction.PoseInteractionClient(channel);
         //wsclient = metagen_comp.Slot.AttachComponent<WebsocketClient>();
         //wsclient.URL.Value = new Uri("http://127.0.0.1:" + (40052).ToString());
         //Acting
         metagen_comp.streamPlayer.PrepareStreamsExternal();
         //RefID user_id = RefID.Parse("IDC00");
         foreach (var item in metagen_comp.streamPlayer.output_writers)
         {
             RefID refID = item.Key;
             pose_writers[refID] = item.Value;
         }
         WriteHeadings();
         metagen_comp.streamPlayer.play_hearing = false;
         metagen_comp.streamPlayer.play_voice   = false;
         UniLog.Log("metagen_comp.botComponent");
         UniLog.Log(metagen_comp.botComponent);
         UniLog.Log("metagen_comp.botComponent.panelUI");
         UniLog.Log(metagen_comp.botComponent.panelUI);
         Slot avatar = metagen_comp.botComponent.panelUI._avatarRefField.Target.Reference.Target;
         metagen_comp.streamPlayer.StartPlayingExternal(1, avatar);
         metagen_comp.metaRecorder.streamRecorder.StartRecordingExternal();
         foreach (var item in metagen_comp.metaRecorder.streamRecorder.output_readers)
         {
             RefID refID = item.Key;
             //BinaryWriterX writer = item.Value;
             //BitReaderStream binaryReader = new BitReaderStream(writer.BaseStream);
             pose_readers[refID] = item.Value;
         }
         ReadHeadings();
         UniLog.Log("Finished starting PoseStreamInteraction");
         isInteracting = true;
     }
     catch (Exception e)
     {
         UniLog.Log("TwT: " + e);
     }
 }
示例#14
0
        public void StartRecording()
        {
            Dictionary <RefID, Slot> avatar_roots = new Dictionary <RefID, Slot>();

            foreach (var item in metagen_comp.userMetaData)
            {
                User         user     = item.Key;
                UserMetadata metadata = item.Value;
                UniLog.Log("user " + user.UserName);
                if (!metadata.isRecording || (metagen_comp.LocalUser == user && !metagen_comp.record_local_user))
                {
                    continue;
                }
                RefID user_id  = user.ReferenceID;
                Slot  rootSlot = user.Root?.Slot;
                avatar_roots[user_id] = rootSlot;
            }
            StartRecordingAvatars(avatar_roots);
        }
示例#15
0
 public void StopRecording()
 {
     isRecording = false;
     boness      = new Dictionary <RefID, IKSolverVR.References>();
     foreach (var item in fileWriters)
     {
         RefID        user_id = item.Key;
         StreamWriter writer  = item.Value;
         writer.Close();
         metagen_comp.RunSynchronously(() =>
         {
             string filename = filenames[user_id];
             UniLog.Log("Import bvh file");
             Slot s = metagen_comp.LocalUserSpace.AddSlot(Path.GetFileName(filename), true);
             metagen_comp.StartGlobalTask((Func <Task>)(async() => await UniversalImporter.ImportRawFile(s, filename)));
         });
     }
     fileWriters        = new Dictionary <RefID, StreamWriter>();
     tracking_rotations = new Dictionary <BodyNode, bool>();
     boness             = new Dictionary <RefID, IKSolverVR.References>();
     filenames          = new Dictionary <RefID, string>();
 }
示例#16
0
 //Record one frame of the head camera for each user
 public void RecordVision()
 {
     foreach (var item in visual_recorders)
     {
         RefID         user_id       = item.Key;
         VideoRecorder videoRecorder = item.Value;
         if (videoRecorder != null && cameras[user_id] != null)
         {
             Task task = metagen_comp.StartTask((Func <Task>)(async() =>
             {
                 Bitmap2D bmp = await cameras[user_id].RenderToBitmap(camera_resolution);
                 visual_recorders[user_id].WriteFrame(bmp.ConvertTo(CodeX.TextureFormat.BGRA32).RawData);
                 //UniLog.Log(DateTime.UtcNow.ToMillisecondTimeString());
             }));
             //TODO: sync video
             //task.Wait();
             //World currentWorld = metagen_comp.World;
             //FrooxEngine.RenderSettings renderSettings = cameras[user_id].GetRenderSettings(camera_resolution);
             //byte[] data = currentWorld.Render.Connector.Render(renderSettings).Result;
             //Bitmap2D bmp = new Bitmap2D(data, renderSettings.size.x, renderSettings.size.y, renderSettings.textureFormat, false, true, (string)null);
             //visual_recorders[user_id].WriteFrame(bmp.ConvertTo(CodeX.TextureFormat.BGRA32).RawData);
         }
         else
         { //something was null:P
             bool vis_rec_null = false;
             bool camera_null  = false;
             if (visual_recorders[user_id] == null)
             {
                 vis_rec_null = true;
             }
             if (cameras[user_id] == null)
             {
                 camera_null = true;
             }
             UniLog.Log("OwO. These things were null: " + (camera_null ? "Camera" : "") + (vis_rec_null ? "Visual recorder" : ""));
         }
     }
 }
示例#17
0
        public void StartRecording()
        {
            source_type = Source.FILE;
            foreach (var userItem in metagen_comp.userMetaData)
            {
                User         user     = userItem.Key;
                UserMetadata metadata = userItem.Value;
                if (!metadata.isRecording || (metagen_comp.LocalUser == user && !metagen_comp.record_local_user))
                {
                    continue;
                }
                RefID user_id          = user.ReferenceID;
                bool  has_eye_tracking = user.Devices.Where <SyncVar>((Func <SyncVar, bool>)(i => i.IsDictionary)).Any <SyncVar>((Func <SyncVar, bool>)(i => i["Type"].GetValue <string>(true) == "Eye Tracking"));

                if (has_eye_tracking)
                {
                    RegisterUserStream(user_id, "eye_streams");
                    eye_streams[user_id] = user.Root.Slot.GetComponent <EyeTrackingStreamManager>();
                    current_eye_tracking_users.Add(user_id);
                }
            }
            isRecording = true;
        }
示例#18
0
 public void RecordFrame()
 {
     foreach (User user in metagen_comp.World.AllUsers)
     {
         RefID user_id = user.ReferenceID;
         if (boness.ContainsKey(user_id))
         {
             IKSolverVR.References bones = boness[user_id];
             BodyNode node = bonesList[0];
             if (bones[node] != null)
             {
                 Slot   bone = bones[node];
                 float3 pos  = bone.GlobalPosition;
                 float3 rot  = bone.GlobalRotation.EulerAngles;
                 fileWriters[user_id].Write(string.Format("{0:0.000000}\t{1:0.000000}\t{2:0.000000}", pos.X, pos.Y, pos.Z) + "\t");
                 fileWriters[user_id].Write(string.Format("{0:0.000000}\t{1:0.000000}\t{2:0.000000}", rot.Z, rot.X, rot.Y) + "\t");
             }
             for (int i = 1; i < bonesList.Count; i++)
             {
                 node = bonesList[i];
                 if (bones[node] != null)
                 {
                     Slot   bone = bones[node];
                     float3 rot  = bone.LocalRotationToSpace(floatQ.Identity, bones[boneParents[node]]).EulerAngles;
                     //float3 rot = bone.LocalRotation.EulerAngles;
                     //float3 pos = bone.LocalPointToSpace(float3.Zero, bones[boneParents[node]]);
                     //float3 rot = floatQ.LookRotation(pos).EulerAngles;
                     if (tracking_rotations[node])
                     {
                         fileWriters[user_id].Write(string.Format("{0:0.000000}\t{1:0.000000}\t{2:0.000000}", rot.Z, rot.X, rot.Y) + "\t");
                     }
                 }
             }
             fileWriters[user_id].Write("\n");
         }
     }
 }
示例#19
0
        private async void StartPlayingInternal()
        {
            try
            {
                if (generateAnimation)
                {
                    metagen_comp.World.RunSynchronously(() =>
                    {
                        animationRecorder = metagen_comp.Slot.AttachComponent <RecordingTool>();
                        animationRecorder.metagen_comp = metagen_comp;
                    });
                }
                //Dictionary<RefID, User>.ValueCollection users = metagen_comp.World.AllUsers;
                avatarManager = new metagen.AvatarManager();
                List <UserMetadata> userMetadatas = new List <UserMetadata>();
                userMetadatas.Add(new UserMetadata {
                    userId = "U-test", bodyNodes = "", devices = "", headDevice = "", isPublic = true, isRecording = true, platform = "", userRefId = "ID2B00"
                });
                Dictionary <RefID, AudioOutput> audio_outputs = new Dictionary <RefID, AudioOutput>();
                foreach (UserMetadata user in userMetadatas)
                {
                    if (!user.isRecording || !user.isPublic)
                    {
                        continue;                                      //at the moment we only allow playing back of public recording, for privacy reasons. In the future, we'll allow private access to the data
                    }
                    RefID user_id = RefID.Parse(user.userRefId);
                    UniLog.Log(user_id.ToString());
                    user_ids.Add(user_id);
                    channel = new Channel("127.0.0.1:" + (40052).ToString(), ChannelCredentials.Insecure);
                    client  = new DataComm.DataCommClient(channel);

                    output_readers[user_id]         = client.GetPose(new Empty()).ResponseStream;
                    fake_proxies[user_id]           = new List <Tuple <BodyNode, AvatarObjectSlot> >();
                    avatar_pose_nodes[user_id]      = new List <Tuple <BodyNode, IAvatarObject> >();
                    avatar_stream_channels[user_id] = new Dictionary <BodyNode, Tuple <bool, bool, bool> >();
                    proxy_slots[user_id]            = new Dictionary <BodyNode, Slot>();
                    if (avatarManager.avatar_template == null && avatar_template != null)
                    {
                        avatarManager.avatar_template = avatar_template;
                    }
                    Slot avatar = await avatarManager.GetAvatar();

                    UniLog.Log("AVATAR");
                    UniLog.Log(avatar.ToString());
                    avatars[user_id] = avatar;
                    List <IAvatarObject>    components = avatar.GetComponentsInChildren <IAvatarObject>();
                    List <AvatarObjectSlot> root_comps = avatar.GetComponentsInChildren <AvatarObjectSlot>();
                    boness[user_id] = avatar.GetComponentInChildren <Rig>()?.Bones.ToList();
                    VRIKAvatar avatarIK = avatar.GetComponentInChildren <VRIKAvatar>();

                    //READ absolute time
                    //output_readers[user_id].ReadSingle();
                    //READ number of body nodes
                    int numBodyNodes = 28; //TODO CHECK
                    for (int i = 0; i < numBodyNodes; i++)
                    {
                        //READ body node type
                        //int nodeInt =
                        //READ if scale stream exists
                        bool scale_exists = true;
                        //READ if position stream exists
                        bool pos_exists = true;
                        //READ if rotation stream exists
                        bool     rot_exists   = true;
                        BodyNode bodyNodeType = VNetcBodyNodeConverter[i];

                        bool node_found = false;
                        foreach (IAvatarObject comp in components)
                        {
                            foreach (AvatarObjectSlot comp2 in root_comps)
                            {
                                if (comp.Node == bodyNodeType && comp2.Node == bodyNodeType)
                                {
                                    UniLog.Log((comp.Node, scale_exists, pos_exists, rot_exists));
                                    if (bodyNodeType == BodyNode.Root)
                                    {
                                        proxy_slots[user_id][bodyNodeType] = avatar;
                                    }
                                    else
                                    {
                                        proxy_slots[user_id][bodyNodeType] = comp.Slot;
                                    }
                                    comp.Equip(comp2);
                                    if (bodyNodeType != BodyNode.Root)
                                    {
                                        SyncRef <Slot> sourceField = (SyncRef <Slot>)comp.GetType().GetField("_source", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(comp);
                                        sourceField.Target = null;
                                        FieldDrive <float3> posField = (FieldDrive <float3>)comp.GetType().GetField("_position", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(comp);
                                        posField.Target = null;
                                        FieldDrive <floatQ> rotField = (FieldDrive <floatQ>)comp.GetType().GetField("_rotation", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(comp);
                                        rotField.Target = null;
                                    }
                                    fake_proxies[user_id].Add(new Tuple <BodyNode, AvatarObjectSlot>(bodyNodeType, comp2));
                                    avatar_pose_nodes[user_id].Add(new Tuple <BodyNode, IAvatarObject>(comp.Node, comp));
                                    comp2.IsTracking.Value = true;
                                    if (bodyNodeType == BodyNode.LeftFoot || bodyNodeType == BodyNode.RightFoot)
                                    {
                                        avatarIK.ForceUseFeetProxies.Value = true;
                                    }
                                    if (bodyNodeType == BodyNode.LeftLowerLeg || bodyNodeType == BodyNode.RightLowerLeg)
                                    {
                                        avatarIK.ForceUseKneeProxies.Value = true;
                                    }
                                    if (bodyNodeType == BodyNode.LeftLowerArm || bodyNodeType == BodyNode.RightLowerArm)
                                    {
                                        avatarIK.ForceUseElbowProxies.Value = true;
                                    }
                                    if (bodyNodeType == BodyNode.Chest)
                                    {
                                        avatarIK.ForceUseChestProxy.Value = true;
                                    }
                                    if (bodyNodeType == BodyNode.Hips)
                                    {
                                        avatarIK.ForceUsePelvisProxy.Value = true;
                                    }
                                    node_found = true;
                                    break;
                                }
                                if (node_found)
                                {
                                    break;
                                }
                            }
                        }
                        //if (!node_found) throw new Exception("Node " + bodyNodeType.ToString() + " not found in avatar!");
                        if (!node_found)
                        {
                            fake_proxies[user_id].Add(new Tuple <BodyNode, AvatarObjectSlot>(bodyNodeType, null));
                            avatar_pose_nodes[user_id].Add(new Tuple <BodyNode, IAvatarObject>(bodyNodeType, null));
                        }
                        avatar_stream_channels[user_id][bodyNodeType] = new Tuple <bool, bool, bool>(scale_exists, pos_exists, rot_exists);
                    }
                    Slot avatarRootSlot = avatar.GetComponentInChildren <AvatarRoot>()?.Slot;
                    if (avatarRootSlot != null)
                    {
                        avatarRootSlot.LocalPosition = new float3(0, 0, 0);
                        avatarRootSlot.LocalRotation = new floatQ(0, 0, 0, 1);
                    }
                    //READ whether hands are being tracked
                    hands_are_tracked[user_id] = false;
                    //READ whether metacarpals are being tracked
                    //output_readers[user_id].ReadBoolean();

                    List <HandPoser> these_hand_posers = avatar.GetComponentsInChildren <HandPoser>(null, excludeDisabled: false, includeLocal: false);
                    UniLog.Log("getting finger rotation vars");
                    finger_slots[user_id]         = new Dictionary <BodyNode, Slot>();
                    hand_posers[user_id]          = new Dictionary <Chirality, HandPoser>();
                    finger_compensations[user_id] = new Dictionary <BodyNode, floatQ>();
                    foreach (HandPoser hand_poser in these_hand_posers)
                    {
                        UniLog.Log("HI");
                        hand_posers[user_id][hand_poser.Side] = hand_poser;
                        BodyNode side1 = BodyNode.LeftThumb_Metacarpal.GetSide((Chirality)hand_poser.Side);
                        BodyNode side2 = BodyNode.LeftPinky_Tip.GetSide((Chirality)hand_poser.Side);
                        for (BodyNode nodee = side1; nodee <= side2; ++nodee)
                        {
                            int                     index             = nodee - side1;
                            FingerType              fingerType        = nodee.GetFingerType();
                            FingerSegmentType       fingerSegmentType = nodee.GetFingerSegmentType();
                            HandPoser.FingerSegment fingerSegment     = hand_poser[fingerType][fingerSegmentType];
                            if (fingerSegment != null && fingerSegment.Root.Target != null)//&& fingerSegment.RotationDrive.IsLinkValid)
                            {
                                UniLog.Log(nodee.ToString());
                                finger_slots[user_id][nodee]         = fingerSegment.Root.Target;
                                proxy_slots[user_id][nodee]          = fingerSegment.Root.Target;
                                finger_compensations[user_id][nodee] = fingerSegment.CoordinateCompensation.Value;
                                fingerSegment.RotationDrive.Target   = (IField <floatQ>)null;
                            }
                        }
                    }
                    UniLog.Log("got finger rotation vars");
                    //AUDIO PLAY
                    audio_outputs[user_id] = null;
                    //UniLog.Log("Setting up audio!");
                    //avatar.GetComponentInChildren<AudioOutput>().Source.Target = null;
                    //for (int i = 0; i < 2; i++)
                    //{
                    //    string audio_file;
                    //    if (i==0)
                    //    {
                    //        if (!play_hearing) continue;
                    //        string[] files = Directory.GetFiles(reading_directory, user_id.ToString() + "*_hearing.ogg");
                    //        audio_file = files.Length > 0 ? files[0] : null;
                    //    } else
                    //    {
                    //        if (!play_voice) continue;
                    //        string[] files = Directory.GetFiles(reading_directory, user_id.ToString() + "*_voice.ogg");
                    //        audio_file = files.Length > 0 ? files[0] : null;
                    //    }
                    //    if (File.Exists(audio_file))
                    //    {
                    //        AudioOutput audio_output = avatar.GetComponentInChildren<AudioOutput>();
                    //        if (audio_output.Source.Target != null) audio_output = audio_output.Slot.AttachComponent<AudioOutput>();
                    //        VisemeAnalyzer visemeAnalyzer = avatar.GetComponentInChildren<VisemeAnalyzer>();
                    //        audio_output.Volume.Value = 1f;
                    //        audio_output.Enabled = true;
                    //        //audio_outputs[user_id] = audio_output;
                    //        //AudioX audioData = new AudioX(reading_directory + "/" + user_id.ToString() + "_audio.wav");
                    //        //AssetRef<AudioClip> audioClip = new AssetRef<AudioClip>();
                    //        Uri uri = this.World.Engine.LocalDB.ImportLocalAsset(audio_file, LocalDB.ImportLocation.Original, (string)null);
                    //        //ToWorld thing = new ToWorld();
                    //        //var awaiter = thing.GetAwaiter();
                    //        //awaiter.GetResult();
                    //        StaticAudioClip audioClip = audio_output.Slot.AttachAudioClip(uri);
                    //        AudioClipPlayer player = audio_output.Slot.AttachComponent<AudioClipPlayer>();
                    //        if (visemeAnalyzer != null)
                    //        {
                    //            visemeAnalyzer.Source.Target = player;
                    //        }
                    //        UniLog.Log("attaching clip to player");
                    //        player.Clip.Target = (IAssetProvider<AudioClip>) audioClip;
                    //        UniLog.Log("attaching player to audio output");
                    //        audio_output.Source.Target = (IAudioSource) player;
                    //        audio_output.Slot.AttachComponent<AudioMetadata>(true, (Action<AudioMetadata>)null).SetFromCurrentWorld();
                    //        player.Play();
                    //    }
                    //}
                }
                avatars_finished_loading = true;
                isPlaying = true;
                if (generateAnimation)
                {
                    animationRecorder.StartRecordingAvatars(avatars, audio_outputs);
                }
                if (generateBvh)
                {
                    bvhRecorder.StartRecordingAvatars(avatars);
                }
            }
            catch (Exception e)
            {
                UniLog.Log("TwT: " + e.Message);
                UniLog.Log(e.StackTrace);
            }
        }
示例#20
0
 //Record one chunk from the voice audio of each user
 public void InteractAudio()
 {
     //Debug.Log("Recording audio");
     foreach (var item in audio_outputs)
     {
         AudioOutput audio_output = item.Value;
         RefID       user_id      = item.Key;
         if (audio_output != null)
         {
             buffer.EnsureSize <float>(metagen_comp.Engine.AudioSystem.BufferSize, false);
             if (audio_output.Source.Target != null)
             {
                 //AudioSystemConnector.InformOfDSPTime(AudioSettings.dspTime);
                 FrooxEngine.Engine.Current.AudioRead();
                 audio_sources_ready = true;
                 AudioStream <MonoSample> stream = (AudioStream <MonoSample>)audio_output.Source.Target;
                 stream.Read <MonoSample>(buffer.AsMonoBuffer());
                 for (int i = 0; i < buffer.Length; i++)
                 {
                     buffer[i] = MathX.Clamp(buffer[i], -1, 1);
                 }
                 float max_val = 0;
                 for (int i = 0; i < buffer.Length; i++)
                 {
                     float val_squared = (float)Math.Pow((double)buffer[i], (double)2);
                     //if (val_squared > max_val) max_val = val_squared;
                     if (val_squared > max_val)
                     {
                         max_val = val_squared;
                         break;
                     }
                 }
                 if (isRecording[user_id])
                 {
                     audio_recorders[user_id].ConvertAndWrite(buffer);
                     //counting the number of consecutive all-zero buffers
                     if (max_val == 0)
                     {
                         number_of_zero_buffers += 1;
                     }
                     else
                     {
                         number_of_zero_buffers = 0;
                     }
                     if (number_of_zero_buffers > zero_buffer_num_threshold)
                     {
                         StopWritingFile(user_id);
                     }
                 }
                 else
                 {
                     //UniLog.Log(max_val);
                     if (max_val > 0)
                     {
                         StartWritingFile(user_id);
                         if (prev_buffer != null)
                         {
                             audio_recorders[user_id].ConvertAndWrite(prev_buffer);
                         }
                         audio_recorders[user_id].ConvertAndWrite(buffer);
                     }
                 }
                 prev_buffer = buffer;
                 //Task.Run(() => { audio_recorders[user_id].ConvertAndWrite(buffer); });
                 //metagen_comp.StartTask(async () => { audio_recorders[user_id].ConvertAndWrite(buffer); });
                 //}
             }
             else
             {
                 UniLog.Log("Audio Output Source target was null! (hmm should we restart it?). Did it happen coz a user left (in which case we shouldn't restart it), or something else?");
                 //UniLog.Log("Restarting audio recording coz audio output source target was null!");
                 //StopRecording();
                 //StartRecording();
             }
         }
     }
 }
示例#21
0
 public void StartRecordingInternal()
 {
     RegisterUserStreams("streams");
     foreach (var userItem in metagen_comp.userMetaData)
     {
         User         user     = userItem.Key;
         UserMetadata metadata = userItem.Value;
         if (!metadata.isRecording || (metagen_comp.LocalUser == user && !metagen_comp.record_local_user))
         {
             continue;
         }
         RefID user_id = user.ReferenceID;
         avatar_stream_drivers[user_id] = new List <Tuple <BodyNode, TransformStreamDriver> >();
         List <AvatarObjectSlot> components = user.Root.Slot.GetComponentsInChildren <AvatarObjectSlot>();
         finger_stream_drivers[user_id]      = user.Root.Slot.GetComponent <FingerPoseStreamManager>();
         avatar_object_slots[user_id]        = new List <Tuple <BodyNode, AvatarObjectSlot> >();
         tracked_device_positioners[user_id] = new List <Tuple <BodyNode, TrackedDevicePositioner> >();
         //WRITE the absolute time
         output_writers[user_id].Write((float)DateTimeOffset.Now.ToUnixTimeMilliseconds()); //absolute time
         int numValidNodes = 0;
         foreach (AvatarObjectSlot comp in components)
         {
             if (comp.IsTracking.Value)
             {
                 if (comp.Node.Value == BodyNode.NONE)
                 {
                     continue;
                 }
                 //if (comp.Node.Value == BodyNode.LeftController || comp.Node.Value == BodyNode.RightController || comp.Node.Value == BodyNode.NONE) continue;
                 //if (comp.Node.Value == BodyNode.LeftHand || comp.Node.Value == BodyNode.RightHand)
                 //{
                 //    TrackedDevicePositioner positioner = comp.Slot.Parent.GetComponent<TrackedDevicePositioner>();
                 //    UniLog.Log(positioner.TrackedDevice.BodyNodePositionOffset);
                 //    UniLog.Log(positioner.TrackedDevice.BodyNodeRotationOffset);
                 //}
                 //avatar_pose_nodes[user_id].Add(new Tuple<BodyNode, IAvatarObject>(comp.Node, comp.Equipped?.Target));
                 avatar_object_slots[user_id].Add(new Tuple <BodyNode, AvatarObjectSlot>(comp.Node, comp));
                 TransformStreamDriver   driver     = comp.Slot.Parent.GetComponent <TransformStreamDriver>();
                 TrackedDevicePositioner positioner = comp.Slot.Parent.GetComponent <TrackedDevicePositioner>();
                 tracked_device_positioners[user_id].Add(new Tuple <BodyNode, TrackedDevicePositioner>(comp.Node.Value, positioner));
                 if (driver != null)
                 {
                     avatar_stream_drivers[user_id].Add(new Tuple <BodyNode, TransformStreamDriver>(comp.Node.Value, driver));
                 }
                 else //if the driver is not in the parent, then it is in the slot (which is what happens for the root)
                 {
                     driver = comp.Slot.GetComponent <TransformStreamDriver>();
                     avatar_stream_drivers[user_id].Add(new Tuple <BodyNode, TransformStreamDriver>(comp.Node.Value, driver));
                 }
                 numValidNodes += 1;
             }
         }
         float3 avatar_root_scale     = user.Root.Slot.GetComponentInChildren <AvatarRoot>().Scale.Value;
         float3 relative_avatar_scale = user.Root.Slot.GetComponentInChildren <AvatarRoot>().Slot.LocalScale / avatar_root_scale;
         //WRITE version identifier
         output_writers[user_id].Write(1001);                    //int
         //WRITE relative avatar scale
         output_writers[user_id].Write(relative_avatar_scale.x); //float
         output_writers[user_id].Write(relative_avatar_scale.y); //float
         output_writers[user_id].Write(relative_avatar_scale.z); //float
         //WRITE the number of body nodes
         output_writers[user_id].Write(numValidNodes);           //int
         foreach (var item in avatar_stream_drivers[user_id])
         {
             TransformStreamDriver driver = item.Item2;
             //WRITE the the body node types
             output_writers[user_id].Write((int)item.Item1);
             //WRITE whether scaleStream is set
             output_writers[user_id].Write(driver.ScaleStream.Target != null);
             //WRITE whether positionStream is set
             output_writers[user_id].Write(driver.PositionStream.Target != null);
             //WRITE whether rotationStream is set
             output_writers[user_id].Write(driver.RotationStream.Target != null);
         }
         //WRITE whether hands are being tracked
         output_writers[user_id].Write(finger_stream_drivers[user_id] != null);
         //WRITE whether metacarpals are tracked (just used as metadata)
         if (finger_stream_drivers[user_id] != null)
         {
             output_writers[user_id].Write(finger_stream_drivers[user_id].TracksMetacarpals);
         }
         else
         {
             output_writers[user_id].Write(false);
         }
         current_users.Add(user_id);
     }
     if (!external_control)
     {
         isRecording = true;
     }
 }
示例#22
0
        public void StartRecording()
        {
            foreach (var userItem in metagen_comp.userMetaData)
            {
                User         user     = userItem.Key;
                UserMetadata metadata = userItem.Value;
                if (!metadata.isRecording || (metagen_comp.LocalUser == user && !metagen_comp.record_local_user))
                {
                    continue;
                }
                RefID user_id = user.ReferenceID;

                InputDeviceStreamDriver inputDeviceStreamDriver = InputDeviceStreamDriverExtensions.GetInputDeviceStreamDriver(user);
                if (inputDeviceStreamDriver != null)
                {
                    RegisterUserStream(user_id, "input_streams");
                    input_streams[user_id] = inputDeviceStreamDriver;
                    current_tracked_users.Add(user_id);
                    digitalStreams[user_id]  = new List <ValueStream <bool> >();
                    analogStreams[user_id]   = new List <ValueStream <float> >();
                    analog2DStreams[user_id] = new List <ValueStream <float2> >();
                    analog3DStreams[user_id] = new List <ValueStream <float3> >();
                    //IStandardController controller = metagen_comp.InputInterface.GetDevice<IStandardController>(d => d.Side == Chirality.Left);
                    foreach (InputDeviceStreamDriver.Device device in inputDeviceStreamDriver.Devices)
                    {
                        //InputDevice inputDevice = metagen_comp.InputInterface.GetDevice<InputDevice>(d => d.DeviceIndex == device.DeviceIndex);
                        //IStandardController controller = inputDevice as IStandardController;
                        //Nullable<Chirality> side = null;
                        //if (controller != null)
                        //{
                        //    side = controller.Side;
                        //}
                        List <Tuple <string, int> > propertyIndices = new List <Tuple <string, int> >();
                        foreach (InputDeviceStreamDriver.Driver <bool> digitalDriver in device.Digital_Drivers)
                        {
                            int index = digitalDriver.PropertyIndex.Value;
                            ValueStream <bool> stream = digitalDriver.Stream.Target;
                            //ControllerProperty property = inputDevice.GetProperty<Digital>(index);
                            //string name = property.Name;
                            string name = stream.Name;
                            propertyIndices.Add(new Tuple <string, int>(name, index));
                            digitalStreams[user_id].Add(stream);
                        }
                        foreach (InputDeviceStreamDriver.Driver <float> analogDriver in device.Analog_Drivers)
                        {
                            int index = analogDriver.PropertyIndex.Value;
                            ValueStream <float> stream = analogDriver.Stream.Target;
                            //ControllerProperty property = inputDevice.GetProperty<Digital>(index);
                            //string name = property.Name;
                            string name = stream.Name;
                            propertyIndices.Add(new Tuple <string, int>(name, index));
                            analogStreams[user_id].Add(stream);
                        }
                        foreach (InputDeviceStreamDriver.Driver <float2> analog2DDriver in device.Analog2D_Drivers)
                        {
                            int index = analog2DDriver.PropertyIndex.Value;
                            ValueStream <float2> stream = analog2DDriver.Stream.Target;
                            //ControllerProperty property = inputDevice.GetProperty<Digital>(index);
                            //string name = property.Name;
                            string name = stream.Name;
                            propertyIndices.Add(new Tuple <string, int>(name, index));
                            analog2DStreams[user_id].Add(stream);
                        }
                        foreach (InputDeviceStreamDriver.Driver <float3> analog3DDriver in device.Analog3D_Drivers)
                        {
                            int index = analog3DDriver.PropertyIndex.Value;
                            ValueStream <float3> stream = analog3DDriver.Stream.Target;
                            //ControllerProperty property = inputDevice.GetProperty<Digital>(index);
                            //string name = property.Name;
                            string name = stream.Name;
                            propertyIndices.Add(new Tuple <string, int>(name, index));
                            analog3DStreams[user_id].Add(stream);
                        }
                        inputDeviceMetadatas[user_id].Add(new InputDeviceMetadata()
                        {
                            //Name = inputDevice.Name,
                            DeviceIndex = device.DeviceIndex,
                            //Type = inputDevice.GetType(),
                            //Side = side,
                            PropertyIndices = propertyIndices
                        });
                    }

                    //WRITE number of input devices
                    output_writers[user_id].Write(inputDeviceMetadatas[user_id].Count);

                    foreach (InputDeviceMetadata inputDeviceMetadata in inputDeviceMetadatas[user_id])
                    {
                        //WRITE device index
                        output_writers[user_id].Write(inputDeviceMetadata.DeviceIndex);
                        //WRITE number of properties for device
                        output_writers[user_id].Write(inputDeviceMetadata.PropertyIndices.Count);
                        foreach (Tuple <string, int> tuple in inputDeviceMetadata.PropertyIndices)
                        {
                            //WRITE property index
                            int index = tuple.Item2;
                            output_writers[user_id].Write(index);
                        }
                    }

                    //CommonToolStreamDriver...
                }
            }
            isRecording = true;
        }
示例#23
0
        public void StartRecording()
        {
            source_type = Source.FILE;
            //NEED to run this world-sycnrhonously
            World currentWorld        = metagen_comp.World;
            int   currentTotalUpdates = currentWorld.TotalUpdates;
            Slot  logix_slot          = metagen_comp.World.RootSlot.AddSlot("temporary logix slot");
            bool  added_logix         = false;

            currentWorld.RunSynchronously(() =>
            {
                foreach (var userItem in metagen_comp.userMetaData)
                {
                    User user             = userItem.Key;
                    UserMetadata metadata = userItem.Value;
                    if (!metadata.isRecording || (metagen_comp.LocalUser == user && !metagen_comp.record_local_user))
                    {
                        continue;
                    }
                    RefID user_id = user.ReferenceID;

                    current_tracked_users.Add(user_id);

                    ReferenceRegister <User> userRegister     = logix_slot.AttachComponent <ReferenceRegister <User> >();
                    userRegister.Target.Target                = user;
                    StandardController standardControllerLeft = logix_slot.AttachComponent <FrooxEngine.LogiX.Input.StandardController>();
                    EnumInput <Chirality> nodeEnum            = logix_slot.AttachComponent <EnumInput <Chirality> >();
                    nodeEnum.Value.Value = Chirality.Left;
                    standardControllerLeft.User.Target = userRegister;
                    standardControllerLeft.Node.Target = nodeEnum;
                    SyncRef <ValueStream <bool> > _primaryStreamLeft   = (SyncRef <ValueStream <bool> >) typeof(StandardController).GetField("_primaryStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerLeft);
                    SyncRef <ValueStream <bool> > _secondaryStreamLeft = (SyncRef <ValueStream <bool> >) typeof(StandardController).GetField("_secondaryStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerLeft);
                    SyncRef <ValueStream <bool> > _grabStreamLeft      = (SyncRef <ValueStream <bool> >) typeof(StandardController).GetField("_grabStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerLeft);
                    SyncRef <ValueStream <bool> > _menuStreamLeft      = (SyncRef <ValueStream <bool> >) typeof(StandardController).GetField("_menuStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerLeft);
                    SyncRef <ValueStream <float> > _strengthStreamLeft = (SyncRef <ValueStream <float> >) typeof(StandardController).GetField("_strengthStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerLeft);
                    SyncRef <ValueStream <float2> > _axisStreamLeft    = (SyncRef <ValueStream <float2> >) typeof(StandardController).GetField("_axisStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerLeft);

                    StandardController standardControllerRight = logix_slot.AttachComponent <FrooxEngine.LogiX.Input.StandardController>();
                    EnumInput <Chirality> nodeEnum2            = logix_slot.AttachComponent <EnumInput <Chirality> >();
                    nodeEnum2.Value.Value = Chirality.Right;
                    standardControllerRight.User.Target = userRegister;
                    standardControllerRight.Node.Target = nodeEnum2;
                    SyncRef <ValueStream <bool> > _primaryStreamRight   = (SyncRef <ValueStream <bool> >) typeof(StandardController).GetField("_primaryStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerRight);
                    SyncRef <ValueStream <bool> > _secondaryStreamRight = (SyncRef <ValueStream <bool> >) typeof(StandardController).GetField("_secondaryStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerRight);
                    SyncRef <ValueStream <bool> > _grabStreamRight      = (SyncRef <ValueStream <bool> >) typeof(StandardController).GetField("_grabStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerRight);
                    SyncRef <ValueStream <bool> > _menuStreamRight      = (SyncRef <ValueStream <bool> >) typeof(StandardController).GetField("_menuStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerRight);
                    SyncRef <ValueStream <float> > _strengthStreamRight = (SyncRef <ValueStream <float> >) typeof(StandardController).GetField("_strengthStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerRight);
                    SyncRef <ValueStream <float2> > _axisStreamRight    = (SyncRef <ValueStream <float2> >) typeof(StandardController).GetField("_axisStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(standardControllerRight);

                    primaryStreamsRefs[user_id]   = new Tuple <SyncRef <ValueStream <bool> >, SyncRef <ValueStream <bool> > >(_primaryStreamLeft, _primaryStreamRight);
                    secondaryStreamsRefs[user_id] = new Tuple <SyncRef <ValueStream <bool> >, SyncRef <ValueStream <bool> > >(_secondaryStreamLeft, _secondaryStreamRight);
                    grabStreamsRefs[user_id]      = new Tuple <SyncRef <ValueStream <bool> >, SyncRef <ValueStream <bool> > >(_grabStreamLeft, _grabStreamRight);
                    menuStreamsRefs[user_id]      = new Tuple <SyncRef <ValueStream <bool> >, SyncRef <ValueStream <bool> > >(_menuStreamLeft, _menuStreamRight);
                    strengthStreamsRefs[user_id]  = new Tuple <SyncRef <ValueStream <float> >, SyncRef <ValueStream <float> > >(_strengthStreamLeft, _strengthStreamRight);
                    axisStreamsRefs[user_id]      = new Tuple <SyncRef <ValueStream <float2> >, SyncRef <ValueStream <float2> > >(_axisStreamLeft, _axisStreamRight);
                }
                added_logix = true;
                UniLog.Log("Added logix");
            });
            metagen_comp.StartTask(async() =>
            {
                Task task = Task.Run(() =>
                {
                    bool all_streams_not_null        = false;
                    List <RefID> good_tracking_users = new List <RefID>();

                    //UniLog.Log("HO");
                    while (!all_streams_not_null & currentWorld.TotalUpdates <= currentTotalUpdates + 60)
                    {
                        if (!added_logix)
                        {
                            continue;
                        }
                        //UniLog.Log("HI");
                        bool all_user_streams_not_null = true;
                        all_streams_not_null           = true;
                        foreach (RefID user_id in current_tracked_users)
                        {
                            //HMM: why does using .Target here rather than .RawTarget give a NullReferenceException??
                            bool primary_streams_not_null   = (primaryStreamsRefs[user_id].Item1.RawTarget != null) & (primaryStreamsRefs[user_id].Item2.RawTarget != null);
                            bool secondary_streams_not_null = (secondaryStreamsRefs[user_id].Item1.RawTarget != null) & (secondaryStreamsRefs[user_id].Item2.RawTarget != null);
                            bool grab_streams_not_null      = (grabStreamsRefs[user_id].Item1.RawTarget != null) & (grabStreamsRefs[user_id].Item2.RawTarget != null);
                            bool menu_streams_not_null      = (menuStreamsRefs[user_id].Item1.RawTarget != null) & (menuStreamsRefs[user_id].Item2.RawTarget != null);
                            bool strength_streams_not_null  = (strengthStreamsRefs[user_id].Item1.RawTarget != null) & (strengthStreamsRefs[user_id].Item2.RawTarget != null);
                            bool axis_streams_not_null      = (axisStreamsRefs[user_id].Item1.RawTarget != null) & (axisStreamsRefs[user_id].Item2.RawTarget != null);

                            all_user_streams_not_null = primary_streams_not_null & secondary_streams_not_null & grab_streams_not_null & menu_streams_not_null & strength_streams_not_null & axis_streams_not_null;

                            if (all_user_streams_not_null)
                            {
                                if (!good_tracking_users.Contains(user_id))
                                {
                                    good_tracking_users.Add(user_id);
                                    UniLog.Log("Added user " + user_id.ToString());
                                }
                            }

                            all_streams_not_null &= all_user_streams_not_null;
                        }
                    }

                    current_tracked_users = good_tracking_users;

                    //Get CommonToolStreamDriver
                    List <RefID> good_tracking_users2 = new List <RefID>();
                    foreach (RefID user_id in current_tracked_users)
                    {
                        User user = currentWorld.GetUser(user_id);
                        List <CommonToolStreamDriver> commonToolStreamDrivers = user.Root.Slot.GetComponents <CommonToolStreamDriver>();
                        ValueStream <bool> primaryBlockedStreamLeft           = null;
                        ValueStream <bool> secondaryBlockedStreamLeft         = null;
                        ValueStream <bool> laserActiveStreamLeft        = null;
                        ValueStream <bool> showLaserToOthersStreamLeft  = null;
                        ValueStream <float3> laserTargetStreamLeft      = null;
                        ValueStream <float> grabDistanceStreamLeft      = null;
                        ValueStream <bool> primaryBlockedStreamRight    = null;
                        ValueStream <bool> secondaryBlockedStreamRight  = null;
                        ValueStream <bool> laserActiveStreamRight       = null;
                        ValueStream <bool> showLaserToOthersStreamRight = null;
                        ValueStream <float3> laserTargetStreamRight     = null;
                        ValueStream <float> grabDistanceStreamRight     = null;
                        foreach (CommonToolStreamDriver driver in commonToolStreamDrivers)
                        {
                            if (driver.Side.Value == Chirality.Left)
                            {
                                primaryBlockedStreamLeft    = driver.PrimaryBlockedStream.Target;
                                secondaryBlockedStreamLeft  = driver.SecondaryBlockedStream.Target;
                                laserActiveStreamLeft       = driver.LaserActiveStream.Target;
                                showLaserToOthersStreamLeft = driver.ShowLaserToOthersStream.Target;
                                laserTargetStreamLeft       = driver.LaserTargetStream.Target;
                                grabDistanceStreamLeft      = driver.GrabDistanceStream.Target;
                            }
                            else if (driver.Side.Value == Chirality.Right)
                            {
                                primaryBlockedStreamRight    = driver.PrimaryBlockedStream.Target;
                                secondaryBlockedStreamRight  = driver.SecondaryBlockedStream.Target;
                                laserActiveStreamRight       = driver.LaserActiveStream.Target;
                                showLaserToOthersStreamRight = driver.ShowLaserToOthersStream.Target;
                                laserTargetStreamRight       = driver.LaserTargetStream.Target;
                                grabDistanceStreamRight      = driver.GrabDistanceStream.Target;
                            }
                        }
                        bool all_common_tool_streams_not_null = primaryBlockedStreamLeft != null & primaryBlockedStreamRight != null
                                                                & secondaryBlockedStreamLeft != null & secondaryBlockedStreamRight != null
                                                                & laserActiveStreamLeft != null & laserActiveStreamRight != null
                                                                & showLaserToOthersStreamLeft != null & showLaserToOthersStreamRight != null
                                                                & laserTargetStreamLeft != null & laserActiveStreamRight != null
                                                                & grabDistanceStreamLeft != null & grabDistanceStreamRight != null;
                        if (all_common_tool_streams_not_null)
                        {
                            good_tracking_users2.Add(user_id);
                            primaryBlockedStreams[user_id]    = new Tuple <ValueStream <bool>, ValueStream <bool> >(primaryBlockedStreamLeft, primaryBlockedStreamRight);
                            secondaryBlockedStreams[user_id]  = new Tuple <ValueStream <bool>, ValueStream <bool> >(secondaryBlockedStreamLeft, secondaryBlockedStreamRight);
                            laserActiveStreams[user_id]       = new Tuple <ValueStream <bool>, ValueStream <bool> >(laserActiveStreamLeft, laserActiveStreamRight);
                            showLaserToOthersStreams[user_id] = new Tuple <ValueStream <bool>, ValueStream <bool> >(showLaserToOthersStreamLeft, showLaserToOthersStreamRight);
                            laserTargetStreams[user_id]       = new Tuple <ValueStream <float3>, ValueStream <float3> >(laserTargetStreamLeft, laserTargetStreamRight);
                            grabDistanceStreams[user_id]      = new Tuple <ValueStream <float>, ValueStream <float> >(grabDistanceStreamLeft, grabDistanceStreamRight);
                        }
                    }
                    current_tracked_users = good_tracking_users2;
                    foreach (RefID user_id in current_tracked_users)
                    {
                        primaryStreams[user_id]   = new Tuple <ValueStream <bool>, ValueStream <bool> >(primaryStreamsRefs[user_id].Item1.RawTarget, primaryStreamsRefs[user_id].Item2.RawTarget);
                        secondaryStreams[user_id] = new Tuple <ValueStream <bool>, ValueStream <bool> >(secondaryStreamsRefs[user_id].Item1.RawTarget, secondaryStreamsRefs[user_id].Item2.RawTarget);
                        grabStreams[user_id]      = new Tuple <ValueStream <bool>, ValueStream <bool> >(grabStreamsRefs[user_id].Item1.RawTarget, grabStreamsRefs[user_id].Item2.RawTarget);
                        menuStreams[user_id]      = new Tuple <ValueStream <bool>, ValueStream <bool> >(menuStreamsRefs[user_id].Item1.RawTarget, menuStreamsRefs[user_id].Item2.RawTarget);
                        strengthStreams[user_id]  = new Tuple <ValueStream <float>, ValueStream <float> >(strengthStreamsRefs[user_id].Item1.RawTarget, strengthStreamsRefs[user_id].Item2.RawTarget);
                        axisStreams[user_id]      = new Tuple <ValueStream <float2>, ValueStream <float2> >(axisStreamsRefs[user_id].Item1.RawTarget, axisStreamsRefs[user_id].Item2.RawTarget);
                        RegisterUserStream(user_id, "controller_streams");
                    }
                    //Destroy LogiX nodes
                    currentWorld.RunSynchronously(() =>
                    {
                        logix_slot.Destroy();
                    });

                    isRecording = true;
                });

                //await CancelAfterAsync(ct=>task, TimeSpan.FromSeconds(30), CancellationToken.None);
                await task;
            });
        }