public void teardown()
        {
            if (client != null)
            {
                client.disconnect();
                client = null;
            }

            if (player != null)
            {
                if (player.engine != null)
                {
                    player.engine.destroy();
                    player.engine = null;
                }
                player = null;
            }
        }
Beispiel #2
0
 public SympleRoster(SympleClient client) : base()
 {
     this.client = client;
 }
        public void initAndStartWebRTC()
        {
#if NETFX_CORE
            JObject CLIENT_OPTIONS = new JObject();
            CLIENT_OPTIONS["secure"]        = true;
            CLIENT_OPTIONS["url"]           = this.SignallingServerUrl;
            CLIENT_OPTIONS["peer"]          = new JObject();
            CLIENT_OPTIONS["peer"]["user"]  = this.LocalPeerUsername;
            CLIENT_OPTIONS["peer"]["name"]  = this.LocalPeerNameLabel;
            CLIENT_OPTIONS["peer"]["group"] = this.LocalPeerGroup;

            SymplePlayerOptions playerOptions = new SymplePlayerOptions();

            playerOptions.userMediaConstraints.audioEnabled = this.AudioEnabled;
            playerOptions.userMediaConstraints.videoEnabled = this.VideoEnabled;
            playerOptions.CoreDispatcher = CoreDispatcher;

            playerOptions.engine = "WebRTC";

            switch (UserType)
            {
            case StarUserType.TRAINEE:
                playerOptions.initiator = true;
                break;

            case StarUserType.MENTOR:
                playerOptions.initiator = false;
                break;

            default:
                break;
            }


            // WebRTC config
            // This is where you would add TURN servers for use in production
            RTCConfiguration WEBRTC_CONFIG = new RTCConfiguration
            {
                IceServers = new List <RTCIceServer> {
                    new RTCIceServer {
                        Url = "stun:stun.l.google.com:19302", Username = string.Empty, Credential = string.Empty
                    },
                    new RTCIceServer {
                        Url = "stun:stun1.l.google.com:19302", Username = string.Empty, Credential = string.Empty
                    },
                    new RTCIceServer {
                        Url = "stun:stun2.l.google.com:19302", Username = string.Empty, Credential = string.Empty
                    },
                    new RTCIceServer {
                        Url = "stun:stun3.l.google.com:19302", Username = string.Empty, Credential = string.Empty
                    },
                    new RTCIceServer {
                        Url = "stun:stun4.l.google.com:19302", Username = string.Empty, Credential = string.Empty
                    },
                    new RTCIceServer {
                        Url = "turn:numb.viagenie.ca", Username = "******", Credential = "0O@S&YfP$@56"
                    }
                }
            };

            playerOptions.rtcConfig = WEBRTC_CONFIG;
            //playerOptions.iceMediaConstraints = asdf; // TODO: not using iceMediaConstraints in latest code?
            playerOptions.onStateChange = (player, state, message) =>
            {
                player.displayStatus(state);
            };

            Messenger.Broadcast(SympleLog.LogTrace, "creating player");
            player = new SymplePlayer(playerOptions);

            Messenger.Broadcast(SympleLog.LogTrace, "creating client");
            client = new SympleClient(CLIENT_OPTIONS);

            client.on("announce", (peer) => {
                Messenger.Broadcast(SympleLog.LogInfo, "Authentication success: " + peer);
            });

            client.on("addPeer", (peerObj) =>
            {
                JObject peer = (JObject)peerObj;

                Messenger.Broadcast(SympleLog.LogInfo, "adding peer: " + peer);


                if (peer["user"] != null)
                {
                    string peerUsername = (string)peer["user"];
                    Messenger.Broadcast(SympleLog.PeerAdded, peerUsername);
                }


                if (this.UserType == StarUserType.TRAINEE)
                {
                    // the TRAINEE user waits for a peer with a specific username, then once it's connected it automatically starts sending video

                    if ((string)peer["user"] == this.ExpectedRemoteVideoReceiverUsername && !videoPeerInitialized)
                    {
                        videoPeerInitialized = true;
                        remoteVideoPeer      = peer;
                        startPlaybackAndRecording();
                    }
                }

                if (this.UserType == StarUserType.MENTOR)
                {
                    // once the MENTOR user sees that the ANNOTATION_RECEIVER user has connected, the MENTOR user keeps track of that peer in order to send annotation messages to it.

                    if ((string)peer["user"] == this.ExpectedRemoteAnnotationReceiverUsername && !annotationPeerInitialized)
                    {
                        annotationPeerInitialized = true;
                        remoteAnnotationPeer      = peer;

                        Messenger.Broadcast(SympleLog.RemoteAnnotationReceiverConnected);

                        // TODO: we could add code here to automatically send any annotation commands that were kept on a queue, so that if the HoloLens drops out and comes back, it can get all the annotations made by the mentor.
                    }
                }
            });

            client.on("presence", (presence) =>
            {
                Messenger.Broadcast(SympleLog.LogDebug, "Recv presence: " + presence);
            });

            client.on("removePeer", (peerObj) =>
            {
                try
                {
                    JObject peer = (JObject)peerObj;

                    Messenger.Broadcast(SympleLog.LogInfo, "Removing peer: " + peer);

                    if (peer != null)
                    {
                        if (peer["user"] != null)
                        {
                            string peerUsername = (string)peer["user"];
                            Messenger.Broadcast(SympleLog.PeerRemoved, peerUsername);
                        }

                        if (remoteVideoPeer != null && remoteVideoPeer["id"].Equals(peer["id"]))
                        {
                            Messenger.Broadcast(SympleLog.LogInfo, "Removing remote video peer");
                            videoPeerInitialized = false;
                            remoteVideoPeer      = null;
                            if (player.engine != null)
                            {
                                player.engine.destroy();
                                player.engine = null;
                            }
                        }

                        /*
                         * if (remoteAnnotationPeer != null && remoteAnnotationPeer["id"].Equals(peer["id"]))
                         * {
                         *  Messenger.Broadcast(SympleLog.LogInfo, "Removing remote annotation peer");
                         *  annotationPeerInitialized = false;
                         *  remoteAnnotationPeer = null;
                         *
                         *  Messenger.Broadcast(SympleLog.RemoteAnnotationReceiverDisconnected);
                         *
                         *  // TODO: we could do some caching of annotation commands locally, in case the peer is reconnecting later in the future.
                         * }
                         */
                    }
                }
                catch (Exception e)
                {
                    Messenger.Broadcast(SympleLog.LogInfo, "caught exception: " + e.Message);
                }
            });

            client.on("message", (mObj) =>
            {
                Messenger.Broadcast(SympleLog.LogTrace, "mObj.GetType().ToString(): " + mObj.GetType().ToString());

                JObject m = (JObject)((Object[])mObj)[0];

                var mFrom = m["from"];

                JToken mFromId = null;

                if (mFrom.Type == JTokenType.Object)
                {
                    mFromId = mFrom["id"];
                }

                /*
                 * if (remotePeer != null && !remotePeer["id"].Equals(mFromId))
                 * {
                 *  Messenger.Broadcast(SympleLog.LogDebug, "Dropping message from unknown peer: " + m);
                 *  return;
                 * }
                 */

                if (m["offer"] != null)
                {
                    switch (UserType)
                    {
                    case StarUserType.TRAINEE:
                        Messenger.Broadcast(SympleLog.LogDebug, "Unexpected offer for one-way streaming");
                        break;

                    case StarUserType.MENTOR:

                        Messenger.Broadcast(SympleLog.LogDebug, "Receive offer: " + m["offer"]);

                        remoteVideoPeer = (JObject)m["from"];

                        JObject playParams = new JObject();
                        // don't set requestedWebRtcCameraIndex here, because that's only for when sending video... instead we want to render whatever video we receive
                        player.play(playParams);

                        var engine = (SymplePlayerEngineWebRTC)player.engine;

                        engine.recvRemoteSDP((JObject)m["offer"]);

                        engine.sendLocalSDP = (desc) =>
                        {
                            Messenger.Broadcast(SympleLog.LogDebug, "Send answer: " + desc);

                            JObject sessionDesc = new JObject();
                            sessionDesc["sdp"]  = desc.Sdp;
                            if (desc.Type == Org.WebRtc.RTCSdpType.Answer)
                            {
                                sessionDesc["type"] = "answer";
                            }
                            else if (desc.Type == Org.WebRtc.RTCSdpType.Offer)
                            {
                                sessionDesc["type"] = "offer";
                            }
                            else if (desc.Type == Org.WebRtc.RTCSdpType.Pranswer)
                            {
                                sessionDesc["type"] = "pranswer";
                            }

                            JObject parameters   = new JObject();
                            parameters["to"]     = remoteVideoPeer;
                            parameters["type"]   = "message";
                            parameters["answer"] = sessionDesc;

                            client.send(parameters);
                        };

                        engine.sendLocalCandidate = (cand) =>
                        {
                            JObject candidateObj          = new JObject();
                            candidateObj["candidate"]     = cand.Candidate;
                            candidateObj["sdpMid"]        = cand.SdpMid;
                            candidateObj["sdpMLineIndex"] = cand.SdpMLineIndex;

                            JObject parameters      = new JObject();
                            parameters["to"]        = remoteVideoPeer;
                            parameters["type"]      = "message";
                            parameters["candidate"] = candidateObj;

                            client.send(parameters);
                        };

                        break;

                    default:
                        break;
                    }
                }
                else if (m["answer"] != null)
                {
                    switch (UserType)
                    {
                    case StarUserType.TRAINEE:

                        SymplePlayerEngineWebRTC engine = (SymplePlayerEngineWebRTC)player.engine;

                        string answerJsonString = JsonConvert.SerializeObject(m["answer"], Formatting.None);

                        JObject answerParams = (JObject)m["answer"];

                        Messenger.Broadcast(SympleLog.LogTrace, "Receive answer: " + answerJsonString);
                        engine.recvRemoteSDP(answerParams);

                        break;

                    case StarUserType.MENTOR:

                        Messenger.Broadcast(SympleLog.LogDebug, "Unexpected answer for one-way streaming");

                        break;

                    default:
                        break;
                    }
                }
                else if (m["candidate"] != null)
                {
                    SymplePlayerEngineWebRTC engine = (SymplePlayerEngineWebRTC)player.engine;

                    JObject candidateParams = (JObject)m["candidate"];

                    Messenger.Broadcast(SympleLog.LogDebug, "Using Candidate: " + candidateParams);
                    engine.recvRemoteCandidate(candidateParams);
                }
                else
                {
                    // the content of the message is unrecognized -- so it might be an annotation command.

                    string jsonMessageString = m.ToString(Formatting.None);
                    Messenger.Broadcast(SympleLog.IncomingMessage, jsonMessageString);
                }
            });

            client.on("disconnect", (peer) =>
            {
                Messenger.Broadcast(SympleLog.LogInfo, "Disconnected from server");
            });

            client.on("error", (error) =>
            {
                Messenger.Broadcast(SympleLog.LogError, "Connection error: " + error);
            });

            client.connect();
#else
            Messenger.Broadcast(SympleLog.LogInfo, "not actually connecting via webrtc because NETFX_CORE not defined (probably this is in the unity editor)");
#endif
        }