/// <inheritdoc/>
        protected override void Dispose(bool disposing)
        {
            if (_nativeHandle != IntPtr.Zero)
            {
                // Unregister the callbacks
                if (_selfHandle != IntPtr.Zero)
                {
                    LocalVideoTrackInterop.LocalVideoTrack_RegisterI420AFrameCallback(_nativeHandle, null, IntPtr.Zero);
                    LocalVideoTrackInterop.LocalVideoTrack_RegisterARGBFrameCallback(_nativeHandle, null, IntPtr.Zero);
                    GCHandle.FromIntPtr(_selfHandle).Free();
                    if (disposing)
                    {
                        _interopCallbackArgs = null;
                    }
                    _selfHandle = IntPtr.Zero;
                }

                // Remove the track from the peer connection, and release the reference
                // to the peer connection.
                if (!_nativePeerHandle.IsClosed)
                {
                    PeerConnectionInterop.PeerConnection_RemoveLocalVideoTrack(_nativePeerHandle, _nativeHandle);
                    _nativePeerHandle.Close();
                }
            }

            if (disposing)
            {
                PeerConnection = null;
            }

            base.Dispose(disposing);
        }
        /// <inheritdoc/>
        public void Dispose()
        {
            if (_nativeHandle.IsClosed)
            {
                return;
            }

            // Remove the track from the peer connection, if any
            PeerConnection?.RemoveLocalVideoTrack(this);
            Debug.Assert(PeerConnection == null); // see OnTrackRemoved

            // Unregister interop callbacks
            if (_selfHandle != IntPtr.Zero)
            {
                LocalVideoTrackInterop.LocalVideoTrack_RegisterI420AFrameCallback(_nativeHandle, null, IntPtr.Zero);
                LocalVideoTrackInterop.LocalVideoTrack_RegisterArgb32FrameCallback(_nativeHandle, null, IntPtr.Zero);
                Utils.ReleaseWrapperRef(_selfHandle);
                _selfHandle          = IntPtr.Zero;
                _interopCallbackArgs = null;
            }

            // Currently there is a 1:1 mapping between track and source, so the track owns its
            // source and must dipose of it.
            Source?.Dispose();

            // Destroy the native object. This may be delayed if a P/Invoke callback is underway,
            // but will be handled at some point anyway, even if the managed instance is gone.
            _nativeHandle.Dispose();
        }
 private void RegisterInteropCallbacks()
 {
     _interopCallbackArgs = new LocalVideoTrackInterop.InteropCallbackArgs()
     {
         Track = this,
         I420AFrameCallback  = LocalVideoTrackInterop.I420AFrameCallback,
         Argb32FrameCallback = LocalVideoTrackInterop.Argb32FrameCallback,
     };
     _selfHandle = Utils.MakeWrapperRef(this);
     LocalVideoTrackInterop.LocalVideoTrack_RegisterI420AFrameCallback(
         _nativeHandle, _interopCallbackArgs.I420AFrameCallback, _selfHandle);
     LocalVideoTrackInterop.LocalVideoTrack_RegisterArgb32FrameCallback(
         _nativeHandle, _interopCallbackArgs.Argb32FrameCallback, _selfHandle);
 }
        /// <summary>
        /// Create a new local video track backed by an existing external video source.
        /// The track can be added to a peer connection by setting the <see cref="Transceiver.LocalVideoTrack"/>
        /// property.
        /// </summary>
        /// <param name="trackName">Name of the new local video track.</param>
        /// <param name="source">External video track source providing some video frames to the track.</param>
        /// <returns>The newly created local video track.</returns>
        /// <seealso cref="Transceiver.LocalVideoTrack"/>
        public static LocalVideoTrack CreateFromExternalSource(string trackName, ExternalVideoTrackSource source)
        {
            if (string.IsNullOrEmpty(trackName))
            {
                trackName = Guid.NewGuid().ToString();
            }

            // Create interop wrappers
            var track = new LocalVideoTrack(trackName, source);

            // Parse settings
            var config = new PeerConnectionInterop.LocalVideoTrackFromExternalSourceInteropInitConfig(trackName, source);

            // Create native implementation objects
            uint res = LocalVideoTrackInterop.LocalVideoTrack_CreateFromExternalSource(config, out LocalVideoTrackHandle trackHandle);

            Utils.ThrowOnErrorCode(res);
            track.SetHandle(trackHandle);
            return(track);
        }
        /// <inheritdoc/>
        public void Dispose()
        {
            if (_nativeHandle.IsClosed)
            {
                return;
            }

            // Notify the source
            if (Source != null)
            {
                Source.OnTrackRemovedFromSource(this);
                Source = null;
            }

            // Remove the track from the peer connection, if any
            if (Transceiver != null)
            {
                Debug.Assert(PeerConnection != null);
                Debug.Assert(Transceiver.LocalTrack == this);
                Transceiver.LocalVideoTrack = null;
            }
            Debug.Assert(PeerConnection == null);
            Debug.Assert(Transceiver == null);

            // Unregister interop callbacks
            if (_selfHandle != IntPtr.Zero)
            {
                LocalVideoTrackInterop.LocalVideoTrack_RegisterI420AFrameCallback(_nativeHandle, null, IntPtr.Zero);
                LocalVideoTrackInterop.LocalVideoTrack_RegisterArgb32FrameCallback(_nativeHandle, null, IntPtr.Zero);
                Utils.ReleaseWrapperRef(_selfHandle);
                _selfHandle          = IntPtr.Zero;
                _interopCallbackArgs = null;
            }

            // Destroy the native object. This may be delayed if a P/Invoke callback is underway,
            // but will be handled at some point anyway, even if the managed instance is gone.
            _nativeHandle.Dispose();
        }
 /// <inheritdoc/>
 protected override void RemoveRef()
 {
     LocalVideoTrackInterop.LocalVideoTrack_RemoveRef(_nativeHandle);
 }