/// <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; }
/// <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; } }
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; } }
/// <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; }
/// <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); } }
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(); }
/// <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(); } }
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);
/// <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); }; }
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; }