// DO NOT EDIT! This is an autogenerated file. All changes will be
// overwritten!

//	Copyright (c) 2023 Vidyo, Inc. All rights reserved.


using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace VidyoClient
{
	/// <summary>
	/// This object represents a virtual renderer on the local endpoint.
	/// </summary>
	public class VirtualRenderer: IDisposable {
		private bool disposed = false; 
#if __IOS__
		const string importLib = "__Internal";
#else
		const string importLib = "libVidyoClient";
#endif
		private IntPtr objPtr; // opaque VidyoVirtualRenderer reference.
		private GCHandle objHandle; // weak VidyoVirtualRenderer reference.
		private List<WeakReference> objects = new List<WeakReference>();

		private void DisposeWeakReferenceObjects() {
			foreach(var item in objects) {
				if (item == null || !item.IsAlive || item.Target == null) { continue; }
				switch (item.Target.GetType().Name) {
					case "VirtualRendererParticipant": ((VirtualRendererParticipant)item.Target).Dispose(false); break;
					case "VirtualRendererStream": ((VirtualRendererStream)item.Target).Dispose(false); break;
				}
			}
			objects.Clear();
		}
		public IntPtr GetObjectPtr() {
			return objPtr;
		}
		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr VidyoVirtualRendererConstructNative(IntPtr id, IntPtr name);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr VidyoVirtualRendererConstructCopyNative(IntPtr other);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern void VidyoVirtualRendererDestructNative(IntPtr obj);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr VidyoVirtualRendererGetIdNative(IntPtr r);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr VidyoVirtualRendererGetNameNative(IntPtr r);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern ulong VidyoVirtualRendererRegisterParticipantsEventListenerNative(IntPtr r, ulong userData, OnParticipantAdded onParticipantAdded, OnParticipantRemoved onParticipantRemoved, OnLoudestParticipantChanged onLoudestParticipantChanged, OnDynamicParticipantChanged onDynamicParticipantChanged, OnAudioLevelChanged onAudioLevelChanged);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern ulong VidyoVirtualRendererRegisterStreamsEventListenerNative(IntPtr r, ulong userData, OnStreamAdded onStreamAdded, OnStreamRemoved onStreamRemoved, OnStreamFrameReceived onStreamsFrame, OnFECCCapabilitiesChanged onFECCCapabilitiesChanged);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern Boolean VidyoVirtualRendererSendFECCCommandsNative(IntPtr r, ulong streamId, IntPtr cmds);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr VidyoVirtualRendererSendFECCCommandsSetcmdsArrayNative(IntPtr obj, IntPtr objArray, int size);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr VidyoVirtualRendererVectorVidyoCameraControlCommandAllocateNative();

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern void VidyoVirtualRendererVectorVidyoCameraControlCommandDeallocateNative(IntPtr param);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern Boolean VidyoVirtualRendererStreamStartNative(IntPtr r, ulong streamId, uint width, uint height, ulong frameInterval, Boolean pin);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern void VidyoVirtualRendererStreamStopNative(IntPtr r, ulong streamId);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern ulong VidyoVirtualRendererUnregisterEventListenerNative(IntPtr r, ulong token);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr VidyoVirtualRendererGetUserDataNative(IntPtr obj);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		public static extern void VidyoVirtualRendererSetUserDataNative(IntPtr obj, IntPtr userData);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnAudioLevelChanged(IntPtr r, IntPtr participant, int energy, Boolean isSpeech, ulong userData);
		private OnAudioLevelChanged _mOnAudioLevelChanged = OnAudioLevelChangedDelegate;
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnDynamicParticipantChanged(IntPtr r, IntPtr selectedParticipants, ulong userData);
		private OnDynamicParticipantChanged _mOnDynamicParticipantChanged = OnDynamicParticipantChangedDelegate;
		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr VidyoVirtualRendererOnDynamicParticipantChangedGetselectedParticipantsArrayNative(IntPtr obj, ref int size);

		[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr VidyoVirtualRendererOnDynamicParticipantChangedFreeselectedParticipantsArrayNative(IntPtr obj, int size);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnFECCCapabilitiesChanged(IntPtr r, IntPtr stream, IntPtr caps, ulong userData);
		private OnFECCCapabilitiesChanged _mOnFECCCapabilitiesChanged = OnFECCCapabilitiesChangedDelegate;
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnLoudestParticipantChanged(IntPtr r, IntPtr participant, Boolean audioOnly, ulong userData);
		private OnLoudestParticipantChanged _mOnLoudestParticipantChanged = OnLoudestParticipantChangedDelegate;
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnParticipantAdded(IntPtr r, IntPtr participant, ulong userData);
		private OnParticipantAdded _mOnParticipantAdded = OnParticipantAddedDelegate;
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnParticipantRemoved(IntPtr r, IntPtr participant, ulong userData);
		private OnParticipantRemoved _mOnParticipantRemoved = OnParticipantRemovedDelegate;
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnStreamAdded(IntPtr r, IntPtr stream, ulong userData);
		private OnStreamAdded _mOnStreamAdded = OnStreamAddedDelegate;
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnStreamFrameReceived(IntPtr r, IntPtr stream, IntPtr videoFrame, ulong userData);
		private OnStreamFrameReceived _mOnStreamFrameReceived = OnStreamFrameReceivedDelegate;
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		private delegate void OnStreamRemoved(IntPtr r, IntPtr stream, ulong userData);
		private OnStreamRemoved _mOnStreamRemoved = OnStreamRemovedDelegate;
		/// <summary>
		/// The video stream type.
		/// </summary>
		public enum VirtualRendererStreamType {
			/// <summary>The source is a participant's video.</summary>
			VirtualrendererstreamtypeVideo,
			/// <summary>The source is a content share video.</summary>
			VirtualrendererstreamtypeContentShare,
			/// <summary>The source type is unknown.</summary>
			VirtualrendererstreamtypeUnknown
		}
		public interface IRegisterParticipantsEventListener{

			void OnParticipantAdded(VirtualRendererParticipant participant, ulong userData);
			void OnParticipantRemoved(VirtualRendererParticipant participant, ulong userData);
			void OnLoudestParticipantChanged(VirtualRendererParticipant participant, Boolean audioOnly, ulong userData);
			void OnDynamicParticipantChanged(List<VirtualRendererParticipant> selectedParticipants, ulong userData);
			void OnAudioLevelChanged(VirtualRendererParticipant participant, int energy, Boolean isSpeech, ulong userData);
		}
		public interface IRegisterStreamsEventListener{

			void OnStreamAdded(VirtualRendererStream stream, ulong userData);
			void OnStreamRemoved(VirtualRendererStream stream, ulong userData);
			void OnStreamFrameReceived(VirtualRendererStream stream, VideoFrame videoFrame, ulong userData);
			void OnFECCCapabilitiesChanged(VirtualRendererStream stream, CameraControlCapabilities caps, ulong userData);
		}
		/// <summary>
		/// The participant information needed for renderer.
		/// </summary>
		public class VirtualRendererParticipant: IDisposable {
			private bool disposed = false; 
#if __IOS__
			const string importLib = "__Internal";
#else
			const string importLib = "libVidyoClient";
#endif
			private IntPtr objPtr; // opaque VidyoVirtualRendererParticipant reference.
			private GCHandle objHandle; // weak VidyoVirtualRendererParticipant reference.
			public IntPtr GetObjectPtr() {
				return objPtr;
			}
			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern IntPtr VidyoVirtualRendererParticipantConstructCopyNative(IntPtr other);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern void VidyoVirtualRendererParticipantDestructNative(IntPtr obj);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern ulong VidyoVirtualRendererParticipantGetIdNative(IntPtr p);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern IntPtr VidyoVirtualRendererParticipantGetInitialNative(IntPtr p);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern IntPtr VidyoVirtualRendererParticipantGetNameNative(IntPtr p);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern IntPtr VidyoVirtualRendererParticipantGetParticipantIdNative(IntPtr p);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			[return: MarshalAs(UnmanagedType.I1)]
			private static extern Boolean VidyoVirtualRendererParticipantIsRemoteNative(IntPtr p);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			public static extern IntPtr VidyoVirtualRendererParticipantGetUserDataNative(IntPtr obj);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			public static extern void VidyoVirtualRendererParticipantSetUserDataNative(IntPtr obj, IntPtr userData);

			public VirtualRendererParticipant(IntPtr other){
				objPtr = VidyoVirtualRendererParticipantConstructCopyNative(other);
				objHandle = GCHandle.Alloc(this, GCHandleType.Weak);
				VidyoVirtualRendererParticipantSetUserDataNative(objPtr, GCHandle.ToIntPtr(objHandle));
			}
			~VirtualRendererParticipant(){
				Dispose(false);
			}
			public void Dispose(){
				Dispose(true);
				GC.SuppressFinalize(this);
			}

			public void Dispose(bool disposing){
				if(disposed) return;

				disposed = true;
				if(objPtr != IntPtr.Zero) {
					VidyoVirtualRendererParticipantSetUserDataNative(objPtr, IntPtr.Zero);
					VidyoVirtualRendererParticipantDestructNative(objPtr);
					objPtr = IntPtr.Zero;
				}

				if(objHandle.IsAllocated) objHandle.Free();
			}

			/// <summary>
			/// Gets participant id.
			/// </summary>
			/// <param name="p">The VidyoVirtualRendererParticipant object.</param>
			public ulong GetId() {
				if (objPtr == IntPtr.Zero) { return default; }

				ulong ret = VidyoVirtualRendererParticipantGetIdNative(objPtr);

				return ret;
			}
			/// <summary>
			/// Gets participant initials.
			/// </summary>
			/// <param name="p">The VidyoVirtualRendererParticipant object.</param>
			public String GetInitial() {
				if (objPtr == IntPtr.Zero) { return default; }

				IntPtr ret = VidyoVirtualRendererParticipantGetInitialNative(objPtr);

				return (string)MarshalPtrToUtf8.GetInstance().MarshalNativeToManaged(ret);
			}
			/// <summary>
			/// Gets participant name.
			/// </summary>
			/// <param name="p">The VidyoVirtualRendererParticipant object.</param>
			public String GetName() {
				if (objPtr == IntPtr.Zero) { return default; }

				IntPtr ret = VidyoVirtualRendererParticipantGetNameNative(objPtr);

				return (string)MarshalPtrToUtf8.GetInstance().MarshalNativeToManaged(ret);
			}
			/// <summary>
			/// Gets participant unique id in the conference.
			/// </summary>
			/// <param name="p">The VidyoVirtualRendererParticipant object.</param>
			public String GetParticipantId() {
				if (objPtr == IntPtr.Zero) { return default; }

				IntPtr ret = VidyoVirtualRendererParticipantGetParticipantIdNative(objPtr);

				return (string)MarshalPtrToUtf8.GetInstance().MarshalNativeToManaged(ret);
			}
			/// <summary>
			/// Checks whether participant is remote.
			/// </summary>
			/// <param name="p">The VidyoVirtualRendererParticipant object.</param>
			public Boolean IsRemote() {
				if (objPtr == IntPtr.Zero) { return default; }

				Boolean ret = VidyoVirtualRendererParticipantIsRemoteNative(objPtr);

				return ret;
			}
		};
		/// <summary>
		/// The stream information needed for renderer.
		/// </summary>
		public class VirtualRendererStream: IDisposable {
			private bool disposed = false; 
#if __IOS__
			const string importLib = "__Internal";
#else
			const string importLib = "libVidyoClient";
#endif
			private IntPtr objPtr; // opaque VidyoVirtualRendererStream reference.
			private GCHandle objHandle; // weak VidyoVirtualRendererStream reference.
			public IntPtr GetObjectPtr() {
				return objPtr;
			}
			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern IntPtr VidyoVirtualRendererStreamConstructCopyNative(IntPtr other);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern void VidyoVirtualRendererStreamDestructNative(IntPtr obj);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern ulong VidyoVirtualRendererStreamGetIdNative(IntPtr s);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern IntPtr VidyoVirtualRendererStreamGetLabelNative(IntPtr s);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			private static extern ulong VidyoVirtualRendererStreamGetParticipantIdNative(IntPtr s);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			[return: MarshalAs(UnmanagedType.I4)]
			private static extern VirtualRenderer.VirtualRendererStreamType VidyoVirtualRendererStreamGetTypeNative(IntPtr s);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			[return: MarshalAs(UnmanagedType.I1)]
			private static extern Boolean VidyoVirtualRendererStreamIsLocalNative(IntPtr s);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			[return: MarshalAs(UnmanagedType.I1)]
			private static extern Boolean VidyoVirtualRendererStreamIsMirroredNative(IntPtr s);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			public static extern IntPtr VidyoVirtualRendererStreamGetUserDataNative(IntPtr obj);

			[DllImport(importLib, CallingConvention = CallingConvention.Cdecl)]
			public static extern void VidyoVirtualRendererStreamSetUserDataNative(IntPtr obj, IntPtr userData);

			public VirtualRendererStream(IntPtr other){
				objPtr = VidyoVirtualRendererStreamConstructCopyNative(other);
				objHandle = GCHandle.Alloc(this, GCHandleType.Weak);
				VidyoVirtualRendererStreamSetUserDataNative(objPtr, GCHandle.ToIntPtr(objHandle));
			}
			~VirtualRendererStream(){
				Dispose(false);
			}
			public void Dispose(){
				Dispose(true);
				GC.SuppressFinalize(this);
			}

			public void Dispose(bool disposing){
				if(disposed) return;

				disposed = true;
				if(objPtr != IntPtr.Zero) {
					VidyoVirtualRendererStreamSetUserDataNative(objPtr, IntPtr.Zero);
					VidyoVirtualRendererStreamDestructNative(objPtr);
					objPtr = IntPtr.Zero;
				}

				if(objHandle.IsAllocated) objHandle.Free();
			}

			/// <summary>
			/// Gets stream id.
			/// </summary>
			/// <param name="s">The VidyoVirtualRendererStream object.</param>
			public ulong GetId() {
				if (objPtr == IntPtr.Zero) { return default; }

				ulong ret = VidyoVirtualRendererStreamGetIdNative(objPtr);

				return ret;
			}
			/// <summary>
			/// Gets stream label.
			/// </summary>
			/// <param name="s">The VidyoVirtualRendererStream object.</param>
			public String GetLabel() {
				if (objPtr == IntPtr.Zero) { return default; }

				IntPtr ret = VidyoVirtualRendererStreamGetLabelNative(objPtr);

				return (string)MarshalPtrToUtf8.GetInstance().MarshalNativeToManaged(ret);
			}
			/// <summary>
			/// Gets streams participant unique id.
			/// </summary>
			/// <param name="s">The VidyoVirtualRendererStream object.</param>
			public ulong GetParticipantId() {
				if (objPtr == IntPtr.Zero) { return default; }

				ulong ret = VidyoVirtualRendererStreamGetParticipantIdNative(objPtr);

				return ret;
			}
			/// <summary>
			/// Gets stream type.
			/// </summary>
			/// <param name="s">The VidyoVirtualRendererStream object.</param>
			public VirtualRenderer.VirtualRendererStreamType GetType() {
				if (objPtr == IntPtr.Zero) { return default; }

				VirtualRenderer.VirtualRendererStreamType ret = VidyoVirtualRendererStreamGetTypeNative(objPtr);

				return ret;
			}
			/// <summary>
			/// Checks whether stream is local.
			/// </summary>
			/// <param name="s">The VidyoVirtualRendererStream object.</param>
			public Boolean IsLocal() {
				if (objPtr == IntPtr.Zero) { return default; }

				Boolean ret = VidyoVirtualRendererStreamIsLocalNative(objPtr);

				return ret;
			}
			/// <summary>
			/// Checks whether stream is mirrored.
			/// </summary>
			/// <param name="s">The VidyoVirtualRendererStream object.</param>
			public Boolean IsMirrored() {
				if (objPtr == IntPtr.Zero) { return default; }

				Boolean ret = VidyoVirtualRendererStreamIsMirroredNative(objPtr);

				return ret;
			}
		};
		private IRegisterParticipantsEventListener _mIRegisterParticipantsEventListener;
		private IRegisterStreamsEventListener _mIRegisterStreamsEventListener;
		/// <summary>
		/// Constructs a virtual renderer.
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		/// <param name="id">Unique ID.</param>
		/// <param name="name">Name of the virtual renderer.</param>
		/// <param name="alloc">The LmiAllocator object.</param>
		public VirtualRenderer(String id, String name) {

			IntPtr nId = MarshalPtrToUtf8.GetInstance().MarshalManagedToNative(id ?? string.Empty);
			IntPtr nName = MarshalPtrToUtf8.GetInstance().MarshalManagedToNative(name ?? string.Empty);
			objPtr = VidyoVirtualRendererConstructNative(nId, nName);
			objHandle = GCHandle.Alloc(this, GCHandleType.Weak);
			Marshal.FreeHGlobal(nName);
			Marshal.FreeHGlobal(nId);
			VidyoVirtualRendererSetUserDataNative(objPtr, GCHandle.ToIntPtr(objHandle));
		}
		public VirtualRenderer(IntPtr other){
			objPtr = VidyoVirtualRendererConstructCopyNative(other);
			objHandle = GCHandle.Alloc(this, GCHandleType.Weak);
			VidyoVirtualRendererSetUserDataNative(objPtr, GCHandle.ToIntPtr(objHandle));
		}
		~VirtualRenderer(){
			Dispose(false);
		}
		public void Dispose(){
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		public void Dispose(bool disposing){
			if(disposed) return;

			disposed = true;
			DisposeWeakReferenceObjects();
			if(objPtr != IntPtr.Zero) {
				VidyoVirtualRendererSetUserDataNative(objPtr, IntPtr.Zero);
				VidyoVirtualRendererDestructNative(objPtr);
				objPtr = IntPtr.Zero;
			}

			if(objHandle.IsAllocated) objHandle.Free();
		}

		/// <summary>
		/// Gets the id of the virtual renderer.
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		public String GetId() {
			if (objPtr == IntPtr.Zero) { return default; }

			IntPtr ret = VidyoVirtualRendererGetIdNative(objPtr);

			return (string)MarshalPtrToUtf8.GetInstance().MarshalNativeToManaged(ret);
		}
		/// <summary>
		/// Gets the name of the virtual renderer.
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		public String GetName() {
			if (objPtr == IntPtr.Zero) { return default; }

			IntPtr ret = VidyoVirtualRendererGetNameNative(objPtr);

			return (string)MarshalPtrToUtf8.GetInstance().MarshalNativeToManaged(ret);
		}
		/// <summary>
		/// Registers virtual renderer callbacks to receive notifications about participants.
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		/// <param name="userData">The user data, returned in callback.</param>
		/// <param name="onParticipantAdded">Notifies the application that the participant added and sends its information.</param>
		/// <param name="onParticipantRemoved">Notifies the application that the participant removed.</param>
		/// <param name="onLoudestParticipantChanged">Notifies the application that the loudest speaker was changed.</param>
		/// <param name="onDynamicParticipantChanged">Reports the list of new dynamic participants.</param>
		/// <param name="onAudioLevelChanged">Notifies the application the audio level of participant was changed.</param>
		public ulong RegisterParticipantsEventListener(ulong userData, IRegisterParticipantsEventListener _iIRegisterParticipantsEventListener) {
			if (objPtr == IntPtr.Zero) { return default; }
			_mIRegisterParticipantsEventListener = _iIRegisterParticipantsEventListener;

			ulong ret = VidyoVirtualRendererRegisterParticipantsEventListenerNative(objPtr, userData, _mOnParticipantAdded, _mOnParticipantRemoved, _mOnLoudestParticipantChanged, _mOnDynamicParticipantChanged, _mOnAudioLevelChanged);

			return ret;
		}
		/// <summary>
		/// Registers virtual renderer callbacks to receive notifications about streams.
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		/// <param name="userData">The user data, returned in callback.</param>
		/// <param name="onStreamAdded">Notifies the application that the stream added and sends its information.</param>
		/// <param name="onStreamRemoved">Notifies the application that the stream removed.</param>
		/// <param name="onStreamsFrame">Notifies the application that the video frame received for stream.</param>
		/// <param name="onFECCCapabilitiesChanged">Notifies the application about the camera control capabilities.</param>
		public ulong RegisterStreamsEventListener(ulong userData, IRegisterStreamsEventListener _iIRegisterStreamsEventListener) {
			if (objPtr == IntPtr.Zero) { return default; }
			_mIRegisterStreamsEventListener = _iIRegisterStreamsEventListener;

			ulong ret = VidyoVirtualRendererRegisterStreamsEventListenerNative(objPtr, userData, _mOnStreamAdded, _mOnStreamRemoved, _mOnStreamFrameReceived, _mOnFECCCapabilitiesChanged);

			return ret;
		}
		/// <summary>
		/// Sends the camera control commands.
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		/// <param name="streamId">The unique ID of stream.</param>
		/// <param name="cmds">Camera control commands.</param>
		public Boolean SendFECCCommands(ulong streamId, List<CameraControlCommand> cmds) {
			if (objPtr == IntPtr.Zero) { return default; }

			IntPtr nListCmds = VidyoVirtualRendererVectorVidyoCameraControlCommandAllocateNative();

			IntPtr nCmds = Marshal.AllocHGlobal(Marshal.SizeOf<IntPtr>() * cmds.Count);
			int nCmdsSize = 0;
			foreach (CameraControlCommand iter in cmds) {
				Marshal.WriteIntPtr(nCmds + (nCmdsSize * Marshal.SizeOf<IntPtr>()), iter.GetObjectPtr());
				nCmdsSize++;
			}
			VidyoVirtualRendererSendFECCCommandsSetcmdsArrayNative(nListCmds, nCmds, nCmdsSize);
			Marshal.FreeHGlobal(nCmds);
			Boolean ret = VidyoVirtualRendererSendFECCCommandsNative(objPtr, streamId, nListCmds);
			VidyoVirtualRendererVectorVidyoCameraControlCommandDeallocateNative(nListCmds);

			return ret;
		}
		/// <summary>
		/// Requests frames for the specific stream with specified parameters or updates stream parameters if frames have already been requested. Parameters are used to request the most suitable video stream for this source. It is set based on tile size..
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		/// <param name="streamId">The unique ID of stream.</param>
		/// <param name="width">Desired stream width.</param>
		/// <param name="height">Desired stream height.</param>
		/// <param name="frameInterval">Desired stream frame interval.</param>
		/// <param name="pin">LMI_TRUE to pin stream to always receive the video frames. LMI_FALSE to make the stream behavior default.</param>
		public Boolean StreamStart(ulong streamId, uint width, uint height, ulong frameInterval, Boolean pin) {
			if (objPtr == IntPtr.Zero) { return default; }

			Boolean ret = VidyoVirtualRendererStreamStartNative(objPtr, streamId, width, height, frameInterval, pin);

			return ret;
		}
		/// <summary>
		/// Stops receiving frames for a specific stream.
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		/// <param name="streamId">The unique ID of stream.</param>
		public void StreamStop(ulong streamId) {
			if (objPtr == IntPtr.Zero) { return; }

			VidyoVirtualRendererStreamStopNative(objPtr, streamId);
		}
		/// <summary>
		/// Unregisters virtual renderer callbacks to receive notifications about participants and streams.
		/// </summary>
		/// <param name="r">The VidyoVirtualRenderer object.</param>
		/// <param name="token">Token for callbacks that should be unregister.</param>
		public ulong UnregisterEventListener(ulong token) {
			if (objPtr == IntPtr.Zero) { return default; }

			ulong ret = VidyoVirtualRendererUnregisterEventListenerNative(objPtr, token);

			return ret;
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnAudioLevelChanged))]
#endif
		private static void OnAudioLevelChangedDelegate(IntPtr r, IntPtr participant, int energy, Boolean isSpeech, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			VirtualRendererParticipant csParticipant = null;
			if(participant != IntPtr.Zero) {
				var csParticipantPtr = VirtualRendererParticipant.VidyoVirtualRendererParticipantGetUserDataNative(participant);
				if (csParticipantPtr == IntPtr.Zero) {
					csParticipant = new VirtualRendererParticipant(participant);
					if (csParticipant != null) {
						csR?.objects?.Add(new WeakReference(csParticipant));
					}
				} else {
					csParticipant = (VirtualRendererParticipant)GCHandle.FromIntPtr(csParticipantPtr).Target;
				}
			}

			csR?._mIRegisterParticipantsEventListener?.OnAudioLevelChanged(csParticipant, energy, isSpeech, userData);
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnDynamicParticipantChanged))]
#endif
		private static void OnDynamicParticipantChangedDelegate(IntPtr r, IntPtr selectedParticipants, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			List<VirtualRendererParticipant> csSelectedParticipants = new List<VirtualRendererParticipant>();
			var nSelectedParticipantsSize = 0;
			var nSelectedParticipants = VidyoVirtualRendererOnDynamicParticipantChangedGetselectedParticipantsArrayNative(selectedParticipants, ref nSelectedParticipantsSize);
			var nSelectedParticipantsIndex = 0;
			while (nSelectedParticipantsIndex < nSelectedParticipantsSize) {
				VirtualRendererParticipant csTselectedParticipants = null;
				if(Marshal.ReadIntPtr(nSelectedParticipants + (nSelectedParticipantsIndex * Marshal.SizeOf(nSelectedParticipants))) != IntPtr.Zero) {
					var csTselectedParticipantsPtr = VirtualRendererParticipant.VidyoVirtualRendererParticipantGetUserDataNative(Marshal.ReadIntPtr(nSelectedParticipants + (nSelectedParticipantsIndex * Marshal.SizeOf(nSelectedParticipants))));
					if (csTselectedParticipantsPtr == IntPtr.Zero) {
						csTselectedParticipants = new VirtualRendererParticipant(Marshal.ReadIntPtr(nSelectedParticipants + (nSelectedParticipantsIndex * Marshal.SizeOf(nSelectedParticipants))));
						if (csTselectedParticipants != null) {
							csR?.objects?.Add(new WeakReference(csTselectedParticipants));
						}
					} else {
						csTselectedParticipants = (VirtualRendererParticipant)GCHandle.FromIntPtr(csTselectedParticipantsPtr).Target;
					}
				}

				csSelectedParticipants.Add(csTselectedParticipants);
				nSelectedParticipantsIndex++;
			}

			csR?._mIRegisterParticipantsEventListener?.OnDynamicParticipantChanged(csSelectedParticipants, userData);
			VidyoVirtualRendererOnDynamicParticipantChangedFreeselectedParticipantsArrayNative(nSelectedParticipants, nSelectedParticipantsSize);
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnFECCCapabilitiesChanged))]
#endif
		private static void OnFECCCapabilitiesChangedDelegate(IntPtr r, IntPtr stream, IntPtr caps, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			VirtualRendererStream csStream = null;
			if(stream != IntPtr.Zero) {
				var csStreamPtr = VirtualRendererStream.VidyoVirtualRendererStreamGetUserDataNative(stream);
				if (csStreamPtr == IntPtr.Zero) {
					csStream = new VirtualRendererStream(stream);
					if (csStream != null) {
						csR?.objects?.Add(new WeakReference(csStream));
					}
				} else {
					csStream = (VirtualRendererStream)GCHandle.FromIntPtr(csStreamPtr).Target;
				}
			}

			CameraControlCapabilities csCaps = new CameraControlCapabilities(caps);
			csR?._mIRegisterStreamsEventListener?.OnFECCCapabilitiesChanged(csStream, csCaps, userData);
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnLoudestParticipantChanged))]
#endif
		private static void OnLoudestParticipantChangedDelegate(IntPtr r, IntPtr participant, Boolean audioOnly, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			VirtualRendererParticipant csParticipant = null;
			if(participant != IntPtr.Zero) {
				var csParticipantPtr = VirtualRendererParticipant.VidyoVirtualRendererParticipantGetUserDataNative(participant);
				if (csParticipantPtr == IntPtr.Zero) {
					csParticipant = new VirtualRendererParticipant(participant);
					if (csParticipant != null) {
						csR?.objects?.Add(new WeakReference(csParticipant));
					}
				} else {
					csParticipant = (VirtualRendererParticipant)GCHandle.FromIntPtr(csParticipantPtr).Target;
				}
			}

			csR?._mIRegisterParticipantsEventListener?.OnLoudestParticipantChanged(csParticipant, audioOnly, userData);
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnParticipantAdded))]
#endif
		private static void OnParticipantAddedDelegate(IntPtr r, IntPtr participant, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			VirtualRendererParticipant csParticipant = null;
			if(participant != IntPtr.Zero) {
				var csParticipantPtr = VirtualRendererParticipant.VidyoVirtualRendererParticipantGetUserDataNative(participant);
				if (csParticipantPtr == IntPtr.Zero) {
					csParticipant = new VirtualRendererParticipant(participant);
					if (csParticipant != null) {
						csR?.objects?.Add(new WeakReference(csParticipant));
					}
				} else {
					csParticipant = (VirtualRendererParticipant)GCHandle.FromIntPtr(csParticipantPtr).Target;
				}
			}

			csR?._mIRegisterParticipantsEventListener?.OnParticipantAdded(csParticipant, userData);
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnParticipantRemoved))]
#endif
		private static void OnParticipantRemovedDelegate(IntPtr r, IntPtr participant, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			VirtualRendererParticipant csParticipant = null;
			if(participant != IntPtr.Zero) {
				var csParticipantPtr = VirtualRendererParticipant.VidyoVirtualRendererParticipantGetUserDataNative(participant);
				if (csParticipantPtr == IntPtr.Zero) {
					csParticipant = new VirtualRendererParticipant(participant);
					if (csParticipant != null) {
						csR?.objects?.Add(new WeakReference(csParticipant));
					}
				} else {
					csParticipant = (VirtualRendererParticipant)GCHandle.FromIntPtr(csParticipantPtr).Target;
				}
			}

			csR?._mIRegisterParticipantsEventListener?.OnParticipantRemoved(csParticipant, userData);
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnStreamAdded))]
#endif
		private static void OnStreamAddedDelegate(IntPtr r, IntPtr stream, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			VirtualRendererStream csStream = null;
			if(stream != IntPtr.Zero) {
				var csStreamPtr = VirtualRendererStream.VidyoVirtualRendererStreamGetUserDataNative(stream);
				if (csStreamPtr == IntPtr.Zero) {
					csStream = new VirtualRendererStream(stream);
					if (csStream != null) {
						csR?.objects?.Add(new WeakReference(csStream));
					}
				} else {
					csStream = (VirtualRendererStream)GCHandle.FromIntPtr(csStreamPtr).Target;
				}
			}

			csR?._mIRegisterStreamsEventListener?.OnStreamAdded(csStream, userData);
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnStreamFrameReceived))]
#endif
		private static void OnStreamFrameReceivedDelegate(IntPtr r, IntPtr stream, IntPtr videoFrame, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			VirtualRendererStream csStream = null;
			if(stream != IntPtr.Zero) {
				var csStreamPtr = VirtualRendererStream.VidyoVirtualRendererStreamGetUserDataNative(stream);
				if (csStreamPtr == IntPtr.Zero) {
					csStream = new VirtualRendererStream(stream);
					if (csStream != null) {
						csR?.objects?.Add(new WeakReference(csStream));
					}
				} else {
					csStream = (VirtualRendererStream)GCHandle.FromIntPtr(csStreamPtr).Target;
				}
			}

			VideoFrame csVideoFrame = null;
			if(videoFrame != IntPtr.Zero) {
				var csVideoFramePtr = VideoFrame.VidyoVideoFrameGetUserDataNative(videoFrame);
				csVideoFrame = csVideoFramePtr == IntPtr.Zero ? new VideoFrame(videoFrame) : (VideoFrame)GCHandle.FromIntPtr(csVideoFramePtr).Target;
			}

			csR?._mIRegisterStreamsEventListener?.OnStreamFrameReceived(csStream, csVideoFrame, userData);
		}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(OnStreamRemoved))]
#endif
		private static void OnStreamRemovedDelegate(IntPtr r, IntPtr stream, ulong userData){
			var csRPtr = r != IntPtr.Zero ? VidyoVirtualRendererGetUserDataNative(r) : IntPtr.Zero;
			if(csRPtr == IntPtr.Zero) return;
			var csR = (VirtualRenderer)GCHandle.FromIntPtr(csRPtr).Target;

			VirtualRendererStream csStream = null;
			if(stream != IntPtr.Zero) {
				var csStreamPtr = VirtualRendererStream.VidyoVirtualRendererStreamGetUserDataNative(stream);
				if (csStreamPtr == IntPtr.Zero) {
					csStream = new VirtualRendererStream(stream);
					if (csStream != null) {
						csR?.objects?.Add(new WeakReference(csStream));
					}
				} else {
					csStream = (VirtualRendererStream)GCHandle.FromIntPtr(csStreamPtr).Target;
				}
			}

			csR?._mIRegisterStreamsEventListener?.OnStreamRemoved(csStream, userData);
		}
	};
}
