Beispiel #1
0
 /// <summary>
 /// Create the underlying native peer connection and its C# wrapper, and register
 /// event handlers for signaling.
 /// </summary>
 private void CreateNativePeerConnection()
 {
     Debug.Assert((_nativePeer == null) || !_nativePeer.Initialized);
     _nativePeer = new WebRTC.PeerConnection();
     _nativePeer.LocalSdpReadytoSend     += Signaler_LocalSdpReadyToSend;
     _nativePeer.IceCandidateReadytoSend += Signaler_IceCandidateReadytoSend;
 }
Beispiel #2
0
        /// <summary>
        /// Uninitialize the underlying WebRTC library, effectively cleaning up the allocated peer connection.
        /// </summary>
        /// <remarks>
        /// <see cref="Peer"/> will be <c>null</c> afterward.
        /// </remarks>
        public void Uninitialize()
        {
            if ((_nativePeer != null) && _nativePeer.Initialized)
            {
                // Fire signals before doing anything else to allow listeners to clean-up,
                // including un-registering any callback and remove any track from the connection.
                OnShutdown.Invoke();

                // Prevent publicly accessing the native peer after it has been deinitialized.
                // This does not prevent systems caching a reference from accessing it, but it
                // is their responsibility to check that the peer is initialized.
                Peer = null;

                // Detach all transceivers. This prevents senders/receivers from trying to access
                // them during their clean-up sequence, as transceivers are about to be destroyed
                // by the native implementation.
                foreach (var mediaLine in _mediaLines)
                {
                    mediaLine.UnpairTransceiver();
                }

                // Close the connection and release native resources.
                _nativePeer.Dispose();
                _nativePeer = null;
            }
        }
Beispiel #3
0
        private async void DoAutoStartActions(WebRTC.PeerConnection nativePeer)
        {
            // If a headset is active then do not capture local streams.
            if (XRDevice.isPresent)
            {
                return;
            }

            if (AutoStartCapture)
            {
                //nativePeer.LocalAudioFrameReady += LocalAudioFrameReady;

                // TODO - Currently AddLocalAudioTrackAsync() both open the capture device AND add an audio track
            }

            if (AutoAddTrack)
            {
                // Force again PreferredAudioCodec right before starting the local capture,
                // so that modifications to the property done after OnPeerInitialized() are
                // accounted for.
                nativePeer.PreferredAudioCodec = PreferredAudioCodec;

                //FrameQueue.Clear();
                await nativePeer.AddLocalAudioTrackAsync();

                AudioStreamStarted.Invoke();
            }
        }
        /// <summary>
        /// Initialize the underlying WebRTC peer connection.
        /// </summary>
        /// <remarks>
        /// This method is asynchronous and completes its task when the initializing completed.
        /// On successful completion, it also trigger the <see cref="OnInitialized"/> event.
        /// Note however that this completion is free-threaded and complete immediately when the
        /// underlying peer connection is initialized, whereas any <see cref="OnInitialized"/>
        /// event handler is invoked when control returns to the main Unity app thread. The former
        /// is faster, but does not allow accessing the underlying peer connection because it
        /// returns before <see cref="OnPostInitialize"/> executed. Therefore it is generally
        /// recommended to listen to the <see cref="OnInitialized"/> event, and ignore the returned
        /// <see xref="System.Threading.Tasks.Task"/> object.
        /// </remarks>
        private async Task <WebRTC.PeerConnection> InitializePluginAsync(CancellationToken token)
        {
            // Ensure Android binding is initialized before accessing the native implementation
            Android.Initialize();

#if UNITY_WSA && !UNITY_EDITOR
            if (Library.UsedAudioDeviceModule == AudioDeviceModule.LegacyModule)
            {
                // Preventing access to audio crashes the ADM1 at startup and the entire application.
                bool permissionGranted = await UwpUtils.RequestAccessAsync(StreamingCaptureMode.Audio);

                if (!permissionGranted)
                {
                    return(null);
                }
            }
#endif
            // Create the peer connection managed wrapper and its native implementation
            var nativePeer = new WebRTC.PeerConnection();

            nativePeer.AudioTrackAdded +=
                (RemoteAudioTrack track) =>
            {
                // Tracks will be output by AudioReceivers, so avoid outputting them twice.
                track.OutputToDevice(false);
            };

            Debug.Log("Initializing WebRTC Peer Connection...");
            var config = new PeerConnectionConfiguration();
            foreach (var server in IceServers)
            {
                config.IceServers.Add(new IceServer
                {
                    Urls         = { server.ToString() },
                    TurnUserName = IceUsername,
                    TurnPassword = IceCredential
                });
            }

            try
            {
                await nativePeer.InitializeAsync(config, token);

                return(nativePeer);
            }
            catch (OperationCanceledException canceled) { throw canceled; }
            catch (Exception ex)
            {
                nativePeer.Dispose();
                token.ThrowIfCancellationRequested();

                EnsureIsMainAppThread();
                var errorMessage = new StringBuilder();
                errorMessage.Append("WebRTC plugin initializing failed. See full log for exception details.\n");
                errorMessage.Append($"Exception: {ex.Message}");
                OnError.Invoke(errorMessage.ToString());
                throw ex;
            }
        }
Beispiel #5
0
        /// <summary>
        /// Callback fired from the <see cref="PeerConnection"/> when it finished
        /// initializing, to subscribe to signaling-related events.
        /// </summary>
        /// <param name="peer">The peer connection to attach to</param>
        public void OnPeerInitialized()
        {
            _nativePeer = PeerConnection.Peer;

            // Register handlers for the SDP events
            _nativePeer.IceCandidateReadytoSend += OnIceCandidateReadyToSend_Listener;
            _nativePeer.LocalSdpReadytoSend     += OnLocalSdpReadyToSend_Listener;
        }
        /// <summary>
        /// Callback fired from the <see cref="PeerConnection"/> when it finished
        /// initializing, to subscribe to signaling-related events.
        /// </summary>
        /// <param name="peer">The peer connection to attach to</param>
        public virtual void OnPeerInitialized(PeerConnection peer)
        {
            PeerConnection = peer;
            _nativePeer    = peer.Peer;

            // Register handlers for the SDP events
            //_nativePeer.IceCandidateReadytoSend += OnIceCandiateReadyToSend_Listener;
            //_nativePeer.LocalSdpReadytoSend += OnLocalSdpReadyToSend_Listener;
        }
Beispiel #7
0
        /// <summary>
        /// Create a new native peer connection and register event handlers to it.
        /// This does not initialize the peer connection yet.
        /// </summary>
        private void CreateNativePeerConnection()
        {
            // Create the peer connection managed wrapper and its native implementation
            _nativePeer = new WebRTC.PeerConnection();

            _nativePeer.AudioTrackAdded +=
                (RemoteAudioTrack track) =>
            {
                // Tracks will be output by AudioReceivers, so avoid outputting them twice.
                track.OutputToDevice(false);
            };
        }
 /// <summary>
 /// creates a dataChannel on the nativePeer and subscribes to its messages.
 /// </summary>
 /// <param name="nativePeer"></param>
 private void DoAutoStartActions(WebRTC.PeerConnection nativePeer)
 {
     //(ushort id), string label, bool ordered, bool reliable
     nativePeer.AddDataChannelAsync((ushort)ChannelID, ChannelID.ToString(), ordered, reliable).ContinueWith((prevTask) =>
     {
         if (prevTask.Exception != null)
         {
             throw prevTask.Exception;
         }
         dataChannel = prevTask.Result;
         dataChannel.MessageReceived += PosMessageReceived;
     });
 }
        private void AddLocalVideoTrackImpl(WebRTC.PeerConnection nativePeer)
        {
            string videoProfileId   = VideoProfileId;
            var    videoProfileKind = VideoProfileKind;
            int    width            = Constraints.width;
            int    height           = Constraints.height;
            double framerate        = Constraints.framerate;

#if ENABLE_WINMD_SUPPORT
            if (Mode == LocalVideoSourceFormatMode.Automatic)
            {
                // Do not constrain resolution by default, unless the device calls for it (see below).
                width  = 0; // auto
                height = 0; // auto

                // Avoid constraining the framerate; this is generally not necessary (formats are listed
                // with higher framerates first) and is error-prone as some formats report 30.0 FPS while
                // others report 29.97 FPS.
                framerate = 0; // auto

                // For HoloLens, use video profile to reduce resolution and save power/CPU/bandwidth
                if (Windows.Graphics.Holographic.HolographicSpace.IsAvailable)
                {
                    if (!Windows.Graphics.Holographic.HolographicDisplay.GetDefault().IsOpaque)
                    {
                        if (Windows.ApplicationModel.Package.Current.Id.Architecture == Windows.System.ProcessorArchitecture.X86)
                        {
                            // Holographic AR (transparent) x86 platform - Assume HoloLens 1
                            videoProfileKind = WebRTC.PeerConnection.VideoProfileKind.VideoRecording; // No profile in VideoConferencing
                            width            = 896;                                                   // Target 896 x 504
                        }
                        else
                        {
                            // Holographic AR (transparent) non-x86 platform - Assume HoloLens 2
                            videoProfileKind = WebRTC.PeerConnection.VideoProfileKind.VideoConferencing;
                            width            = 1280; // Target 1280 x 720
                        }
                    }
                }
            }
#endif
            // Force again PreferredVideoCodec right before starting the local capture,
            // so that modifications to the property done after OnPeerInitialized() are
            // accounted for.
            nativePeer.PreferredVideoCodec = PreferredVideoCodec;

            FrameQueue.Clear();
            var trackSettings = new WebRTC.PeerConnection.LocalVideoTrackSettings
            {
                videoDevice                 = default,
        private void DoAutoStartActions(WebRTC.PeerConnection nativePeer)
        {
            if (AutoStartCapture)
            {
                nativePeer.I420LocalVideoFrameReady += I420LocalVideoFrameReady;

                // TODO - Currently AddLocalVideoTrackAsync() both open the capture device AND add a video track
            }

            if (AutoAddTrack)
            {
                AddLocalVideoTrackImpl(nativePeer);
            }
        }
Beispiel #11
0
        private async void DoAutoStartActions(WebRTC.PeerConnection nativePeer)
        {
            if (AutoAddTrack)
            {
                // This needs to be awaited because it will initialize Track, used below
                await AddLocalVideoTrackImplAsync(nativePeer);
            }

            if (AutoStartCapture && (Track != null))
            {
                Track.I420AVideoFrameReady += I420ALocalVideoFrameReady;
                // TODO - Currently AddLocalVideoTrackAsync() both open the capture device AND add a video track
            }
        }
        /// <summary>
        /// Callback fired on the main UI thread once the WebRTC plugin was initialized successfully.
        /// </summary>
        private void OnPostInitialize()
        {
            Debug.Log("WebRTC plugin initialized successfully.");

            // Once the peer is initialized, it becomes publicly accessible.
            // This prevent scripts from accessing it before it is initialized,
            // or worse before it is constructed in Awake(). This happens because
            // some scripts try to access Peer in OnEnabled(), which won't work
            // if Unity decided to initialize that script before the current one.
            // However subsequent calls will (and should) work as expected.
            Peer = _nativePeer;

            Signaler.OnPeerInitialized(this);
            OnInitialized.Invoke();
        }
Beispiel #13
0
        /// <summary>
        /// Uninitialize the underlying WebRTC library, effectively cleaning up the allocated peer connection.
        /// </summary>
        /// <remarks>
        /// <see cref="Peer"/> will be <c>null</c> afterward.
        /// </remarks>
        public void Uninitialize()
        {
            if ((_nativePeer != null) && _nativePeer.Initialized)
            {
                // Fire signals before doing anything else to allow listeners to clean-up,
                // including un-registering any callback and remove any track from the connection.
                OnShutdown.Invoke();
                Signaler.OnPeerUninitializing(this);

                // Prevent publicly accessing the native peer after it has been deinitialized.
                // This does not prevent systems caching a reference from accessing it, but it
                // is their responsibility to check that the peer is initialized.
                Peer = null;

                // Close the connection and release native resources.
                _nativePeer.Dispose();
            }
        }
Beispiel #14
0
        private async void DoAutoStartActions(WebRTC.PeerConnection nativePeer)
        {
            if (AutoStartCapture)
            {
                nativePeer.I420LocalVideoFrameReady += I420LocalVideoFrameReady;

                // TODO - Currently AddLocalVideoTrackAsync() both open the capture device AND add a video track
            }

            if (AutoAddTrack)
            {
                // Force again PreferredVideoCodec right before starting the local capture,
                // so that modifications to the property done after OnPeerInitialized() are
                // accounted for.
                nativePeer.PreferredVideoCodec = PreferredVideoCodec;

                FrameQueue.Clear();
                await nativePeer.AddLocalVideoTrackAsync(default, EnableMixedRealityCapture);
Beispiel #15
0
        /// <summary>
        /// Create a new native peer connection and register event handlers to it.
        /// This does not initialize the peer connection yet.
        /// </summary>
        private void CreateNativePeerConnection()
        {
            // Create the peer connection managed wrapper and its native implementation
            _nativePeer = new WebRTC.PeerConnection();

            // Register event handlers for remote tracks removed (media receivers).
            // Note that handling of tracks added is done in HandleConnectionMessageAsync rather than
            // in TrackAdded because when these are invoked the transceivers have not been
            // paired yet, so there's not much we can do with those events.
            _nativePeer.AudioTrackRemoved += Peer_AudioTrackRemoved;
            _nativePeer.VideoTrackRemoved += Peer_VideoTrackRemoved;

            _nativePeer.AudioTrackAdded +=
                (RemoteAudioTrack track) =>
            {
                // Tracks will be output by AudioReceivers, so avoid outputting them twice.
                track.OutputToDevice(false);
            };
        }
Beispiel #16
0
 private void Awake()
 {
     _nativePeer = new WebRTC.PeerConnection(Signaler);
 }
        /// <summary>
        /// Initialize the underlying WebRTC libraries
        /// </summary>
        /// <remarks>
        /// This function is asynchronous, to monitor it's status bind a handler to OnInitialized and OnError
        /// </remarks>
        public Task InitializeAsync(CancellationToken token = default(CancellationToken))
        {
            // Normally would be initialized by Awake(), but in case the component is disabled
            if (_nativePeer == null)
            {
                _nativePeer = new WebRTC.PeerConnection();
                _nativePeer.LocalSdpReadytoSend     += Signaler_LocalSdpReadyToSend;
                _nativePeer.IceCandidateReadytoSend += Signaler_IceCandidateReadytoSend;
            }

            // if the peer is already set, we refuse to initialize again.
            // Note: for multi-peer scenarios, use multiple WebRTC components.
            if (_nativePeer.Initialized)
            {
                return(Task.CompletedTask);
            }

#if UNITY_ANDROID
            AndroidJavaClass systemClass = new AndroidJavaClass("java.lang.System");
            string           libname     = "jingle_peerconnection_so";
            systemClass.CallStatic("loadLibrary", new object[1] {
                libname
            });
            Debug.Log("loadLibrary loaded : " + libname);

            /*
             * Below is equivalent of this java code:
             * PeerConnectionFactory.InitializationOptions.Builder builder =
             *   PeerConnectionFactory.InitializationOptions.builder(UnityPlayer.currentActivity);
             * PeerConnectionFactory.InitializationOptions options =
             *   builder.createInitializationOptions();
             * PeerConnectionFactory.initialize(options);
             */

            AndroidJavaClass  playerClass      = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject activity         = playerClass.GetStatic <AndroidJavaObject>("currentActivity");
            AndroidJavaClass  webrtcClass      = new AndroidJavaClass("org.webrtc.PeerConnectionFactory");
            AndroidJavaClass  initOptionsClass = new AndroidJavaClass("org.webrtc.PeerConnectionFactory$InitializationOptions");
            AndroidJavaObject builder          = initOptionsClass.CallStatic <AndroidJavaObject>("builder", new object[1] {
                activity
            });
            AndroidJavaObject options = builder.Call <AndroidJavaObject>("createInitializationOptions");

            if (webrtcClass != null)
            {
                webrtcClass.CallStatic("initialize", new object[1] {
                    options
                });
            }
#endif

#if UNITY_WSA && !UNITY_EDITOR
            if (UnityEngine.WSA.Application.RunningOnUIThread())
#endif
            {
                return(RequestAccessAndInitAsync(token));
            }
#if UNITY_WSA && !UNITY_EDITOR
            else
            {
                UnityEngine.WSA.Application.InvokeOnUIThread(() => RequestAccessAndInitAsync(token), waitUntilDone: true);
                return(Task.CompletedTask);
            }
#endif
        }
 private void Awake()
 {
     _nativePeer = new WebRTC.PeerConnection();
     _nativePeer.LocalSdpReadytoSend     += Signaler_LocalSdpReadyToSend;
     _nativePeer.IceCandidateReadytoSend += Signaler_IceCandidateReadytoSend;
 }