linphone-ios/wrappers/csharp/wrapper_impl.mustache
2017-08-24 12:12:59 +02:00

556 lines
17 KiB
Text

/*
LinphoneWrapper.cs
Copyright (C) 2017 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
#if __IOS__
using ObjCRuntime;
#endif
namespace Linphone
{
#region Wrapper specifics
/// <summary>
/// Only contains the LIB_NAME value that represents the library in which all DllImport are made
/// </summary>
public class LinphoneWrapper
{
#if __IOS__
public const string LIB_NAME = "linphone.framework/linphone";
#else
public const string LIB_NAME = "linphone"; // With this, it automatically finds liblinphone.so
#endif
#if WINDOWS_UWP
public const string BELLE_SIP_LIB_NAME = "bellesip";
public const string BCTOOLBOX_LIB_NAME = "bctoolbox";
#else
public const string BELLE_SIP_LIB_NAME = "linphone";
public const string BCTOOLBOX_LIB_NAME = "linphone";
#endif
#if ANDROID
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern void setAndroidLogHandler();
#endif
#if __IOS__
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern void linphone_iphone_enable_logs();
#endif
/// <summary>
/// Registers the native log handler in Linphone.
/// </summary>
public static void setNativeLogHandler()
{
#if ANDROID
setAndroidLogHandler();
#elif __IOS__
linphone_iphone_enable_logs();
#endif
}
}
/// <summary>
/// All methods that returns a LinphoneStatus with a value != 0 as an error code in C are translated in C# by throwing a LinphoneException
/// </summary>
#if WINDOWS_UWP
public class LinphoneException : System.Exception
{
public LinphoneException() : base() { }
public LinphoneException(string message) : base(message) { }
public LinphoneException(string message, System.Exception inner) : base(message, inner) { }
}
#else
[Serializable()]
public class LinphoneException : System.Exception
{
public LinphoneException() : base() { }
public LinphoneException(string message) : base(message) { }
public LinphoneException(string message, System.Exception inner) : base(message, inner) { }
protected LinphoneException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
}
#endif
[StructLayout(LayoutKind.Sequential)]
/// <summary>
/// Parent class for a Linphone public objects
/// </summary>
public class LinphoneObject
{
internal IntPtr nativePtr;
internal GCHandle handle;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void OnLinphoneObjectDataDestroyed(IntPtr data);
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME)]
#if WINDOWS_UWP
static extern int belle_sip_object_data_set(IntPtr ptr, string name, IntPtr data, IntPtr cb);
#else
static extern int belle_sip_object_data_set(IntPtr ptr, string name, IntPtr data, OnLinphoneObjectDataDestroyed cb);
#endif
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME)]
static extern IntPtr belle_sip_object_data_get(IntPtr ptr, string name);
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME)]
static extern IntPtr belle_sip_object_ref(IntPtr ptr);
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME)]
static extern void belle_sip_object_unref(IntPtr ptr);
[DllImport(LinphoneWrapper.BELLE_SIP_LIB_NAME)]
static extern void belle_sip_object_data_remove(IntPtr ptr, string data);
[DllImport(LinphoneWrapper.BCTOOLBOX_LIB_NAME)]
static extern IntPtr bctbx_list_next(IntPtr ptr);
[DllImport(LinphoneWrapper.BCTOOLBOX_LIB_NAME)]
static extern IntPtr bctbx_list_get_data(IntPtr ptr);
[DllImport(LinphoneWrapper.BCTOOLBOX_LIB_NAME)]
static extern IntPtr bctbx_list_append(IntPtr elem, string data);
[DllImport(LinphoneWrapper.BCTOOLBOX_LIB_NAME)]
static extern IntPtr bctbx_list_append(IntPtr elem, IntPtr data);
#if __IOS__
[MonoPInvokeCallback(typeof(OnLinphoneObjectDataDestroyed))]
#endif
~LinphoneObject()
{
//Console.WriteLine("Destroying " + this.ToString());
if (nativePtr != IntPtr.Zero) {
//Console.WriteLine("Unreffing " + this.ToString());
belle_sip_object_data_remove(nativePtr, "cs_obj");
belle_sip_object_unref(nativePtr);
handle.Free();
}
}
internal static T fromNativePtr<T>(IntPtr ptr, bool takeRef=true) where T : LinphoneObject, new()
{
if (ptr == IntPtr.Zero) return null;
IntPtr objPtr = belle_sip_object_data_get(ptr, "cs_obj");
if (objPtr != IntPtr.Zero)
{
T obj = null;
GCHandle handle = GCHandle.FromIntPtr(objPtr);
if (handle.IsAllocated)
{
obj = (T)handle.Target;
}
if (obj == null)
{
//Console.WriteLine("Handle target is null " + handle.Target);
objPtr = IntPtr.Zero;
}
else
{
//Console.WriteLine("Using existing " + obj.ToString());
return obj;
}
}
if (objPtr == IntPtr.Zero)
{
T obj = new T();
//Console.WriteLine("Creating " + obj.ToString());
if (takeRef)
{
ptr = belle_sip_object_ref(ptr);
//Console.WriteLine("Reffing " + obj.ToString());
}
obj.nativePtr = ptr;
obj.handle = GCHandle.Alloc(obj, GCHandleType.WeakTrackResurrection);
objPtr = GCHandle.ToIntPtr(obj.handle);
belle_sip_object_data_set(ptr, "cs_obj", objPtr, IntPtr.Zero);
return obj;
}
return null;
}
internal static IEnumerable<string> MarshalStringArray(IntPtr arrayPtr)
{
if (arrayPtr != IntPtr.Zero)
{
IntPtr ptr = Marshal.ReadIntPtr(arrayPtr);
while (ptr != IntPtr.Zero)
{
string key = Marshal.PtrToStringAnsi(ptr);
yield return key;
arrayPtr = new IntPtr(arrayPtr.ToInt64() + IntPtr.Size);
ptr = Marshal.ReadIntPtr(arrayPtr);
}
}
}
internal static IEnumerable<T> MarshalBctbxList<T>(IntPtr listPtr) where T : LinphoneObject, new()
{
if (listPtr != IntPtr.Zero)
{
IntPtr ptr = listPtr;
while (ptr != IntPtr.Zero)
{
IntPtr dataPtr = bctbx_list_get_data(ptr);
if (dataPtr == IntPtr.Zero)
{
break;
}
T obj = fromNativePtr<T>(dataPtr);
yield return obj;
ptr = bctbx_list_next(ptr);
}
}
}
internal static IntPtr StringArrayToBctbxList(IEnumerable<string> stringlist)
{
IntPtr bctbx_list = IntPtr.Zero;
foreach (string s in stringlist)
{
bctbx_list = bctbx_list_append(bctbx_list, s);
}
return bctbx_list;
}
internal static IntPtr ObjectArrayToBctbxList<T>(IEnumerable<T> objlist) where T : LinphoneObject, new()
{
IntPtr bctbx_list = IntPtr.Zero;
foreach (T ptr in objlist)
{
bctbx_list = bctbx_list_append(bctbx_list, ptr.nativePtr);
}
return bctbx_list;
}
}
#if ANDROID
/// <summary>
/// Methods that are only found in Android version of Linphone libraries and related to JNI
/// </summary>
public class LinphoneAndroid
{
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern void ms_set_jvm_from_env(IntPtr jnienv);
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern void setMediastreamerAndroidContext(IntPtr jnienv, IntPtr context);
/// <summary>
/// Sets the JVM and JNI pointers in Linphone, required to be able to make JAVA upcalls.
/// Calling this method is mandatory and must be done as soon as possible !
/// </summary>
public static void setAndroidContext(IntPtr jnienv, IntPtr context)
{
ms_set_jvm_from_env(jnienv);
setMediastreamerAndroidContext(jnienv, context);
}
}
#endif
#endregion
#region Enums
{{#enums}}
{{#enum}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}
public enum {{enumName}}
{
{{#values}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}
{{name}} = {{value}},
{{/values}}
}
{{/enum}}
{{/enums}}
#endregion
#region Listeners
{{#interfaces}}
{{#interface}}
[StructLayout(LayoutKind.Sequential)]
public class {{interfaceName}} : LinphoneObject
{
{{#methods}}
[DllImport(LinphoneWrapper.LIB_NAME)]
{{#cb_setter}}
#if WINDOWS_UWP
static extern void {{name}}(IntPtr thiz, IntPtr cb);
#else
static extern void {{name}}(IntPtr thiz, {{name_private}} cb);
#endif
{{/cb_setter}}
{{#delegate}}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void {{name_private}}({{params_private}});
public delegate void {{name_public}}({{params_public}});
private {{name_private}} {{var_private}};
private {{name_public}} {{var_public}};
#if __IOS__
[MonoPInvokeCallback(typeof({{name_private}}))]
#endif
private static void {{cb_name}}({{params_private}})
{
{{interfaceClassName}} thiz = fromNativePtr<{{interfaceClassName}}>({{first_param}});
{{#isSimpleListener}}{{interfaceName}} listener = thiz.Listener;{{/isSimpleListener}}
{{#isMultiListener}}{{interfaceName}} listener = thiz.CurrentCallbacks;{{/isMultiListener}}
listener.{{var_public}}?.Invoke({{{params}}});
}
public {{name_public}} {{name}}
{
get
{
return {{var_public}};
}
set
{
{{var_public}} = value;
#if WINDOWS_UWP
{{var_private}} = {{cb_name}};
IntPtr cb = Marshal.GetFunctionPointerForDelegate({{var_private}});
{{c_name_setter}}(nativePtr, cb);
#else
{{c_name_setter}}(nativePtr, {{cb_name}});
#endif
}
}
{{/delegate}}
{{/methods}}
}
{{/interface}}
{{/interfaces}}
#endregion
#region Classes
{{#classes}}
{{#_class}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}
[StructLayout(LayoutKind.Sequential)]
public class {{className}} : LinphoneObject
{
{{#isLinphoneFactory}}
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern IntPtr linphone_factory_create_core_cbs(IntPtr factory);
public CoreListener CreateCoreListener()
{
IntPtr coreCbsPtr = linphone_factory_create_core_cbs(nativePtr);
return fromNativePtr<CoreListener>(coreCbsPtr, false);
}
{{/isLinphoneFactory}}
{{#isLinphoneCall}}
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern IntPtr linphone_call_get_native_video_window_id(IntPtr thiz);
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern void linphone_call_set_native_video_window_id(IntPtr thiz, IntPtr id);
/// Get the native window handle of the video window, casted as an unsigned long.
public string NativeVideoWindowId
{
get
{
return Marshal.PtrToStringUni(linphone_call_get_native_video_window_id(nativePtr));
}
set
{
linphone_call_set_native_video_window_id(nativePtr, Marshal.StringToHGlobalUni(value));
}
}
{{/isLinphoneCall}}
{{#isLinphoneCore}}
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern IntPtr linphone_core_get_native_video_window_id(IntPtr thiz);
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern void linphone_core_set_native_video_window_id(IntPtr thiz, IntPtr id);
/// Get the native window handle of the video window.
public string NativeVideoWindowId
{
get
{
return Marshal.PtrToStringUni(linphone_core_get_native_video_window_id(nativePtr));
}
set
{
linphone_core_set_native_video_window_id(nativePtr, Marshal.StringToHGlobalUni(value));
}
}
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern IntPtr linphone_core_get_native_preview_window_id(IntPtr thiz);
[DllImport(LinphoneWrapper.LIB_NAME)]
static extern void linphone_core_set_native_preview_window_id(IntPtr thiz, IntPtr id);
/// Get the native window handle of the video preview window.
public string NativePreviewWindowId
{
get
{
return Marshal.PtrToStringUni(linphone_core_get_native_preview_window_id(nativePtr));
}
set
{
linphone_core_set_native_preview_window_id(nativePtr, Marshal.StringToHGlobalUni(value));
}
}
{{/isLinphoneCore}}
{{#dllImports}}
[DllImport(LinphoneWrapper.LIB_NAME)]
{{{prototype}}}
{{#has_second_prototype}}
[DllImport(LinphoneWrapper.LIB_NAME)]
{{second_prototype}}
{{/has_second_prototype}}
{{#has_property}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}
{{property_static}}public {{{property_return}}} {{property_name}}
{
{{#has_getter}}
get
{
{{#is_string}}
IntPtr stringPtr = {{getter_c_name}}({{getter_nativePtr}});
return Marshal.PtrToStringAnsi(stringPtr);
{{/is_string}}
{{#is_bool}}
return {{getter_c_name}}({{getter_nativePtr}}) != 0;
{{/is_bool}}
{{#is_class}}
IntPtr ptr = {{getter_c_name}}({{getter_nativePtr}});
return fromNativePtr<{{return}}>(ptr, {{takeRef}});
{{/is_class}}
{{#is_enum}}
return {{getter_c_name}}({{getter_nativePtr}});
{{/is_enum}}
{{#is_generic}}
return {{getter_c_name}}({{getter_nativePtr}});
{{/is_generic}}
{{#is_string_list}}
return MarshalStringArray({{getter_c_name}}({{getter_nativePtr}}));
{{/is_string_list}}
{{#is_class_list}}
return MarshalBctbxList<{{{list_type}}}>({{getter_c_name}}({{getter_nativePtr}}));
{{/is_class_list}}
}
{{/has_getter}}
{{#has_setter}}
set
{
{{#is_string}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_string}}
{{#is_bool}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value ? 1 : 0);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_bool}}
{{#is_class}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value.nativePtr);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_class}}
{{#is_enum}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}(int)value);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_enum}}
{{#is_generic}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value);
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_generic}}
{{#is_string_list}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}StringArrayToBctbxList(value));
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_string_list}}
{{#is_class_list}}
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}ObjectArrayToBctbxList<{{{list_type}}}>(value));
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
{{/is_class_list}}
}
{{/has_setter}}
}
{{/has_property}}
{{#has_impl}}
{{#impl}}
{{#doc}}
{{#lines}}
/// {{{line}}}
{{/lines}}
{{/doc}}
public {{static}}{{override}}{{{type}}} {{name}}({{{args}}})
{
{{#is_string}}
IntPtr stringPtr = {{c_name}}({{nativePtr}}{{c_args}});
return Marshal.PtrToStringAnsi(stringPtr);
{{/is_string}}
{{#is_bool}}
{{return}}{{c_name}}({{nativePtr}}{{c_args}}) == 0 ? false : true;
{{/is_bool}}
{{#is_class}}
IntPtr ptr = {{c_name}}({{nativePtr}}{{c_args}});
return fromNativePtr<{{type}}>(ptr, {{takeRef}});
{{/is_class}}
{{#is_enum}}
{{#exception}}int exception_result = {{/exception}}{{return}}{{c_name}}({{nativePtr}}{{{c_args}}});
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{name}} returned value " + exception_result);{{/exception}}
{{/is_enum}}
{{#is_generic}}
{{#exception}}int exception_result = {{/exception}}{{return}}{{c_name}}({{nativePtr}}{{{c_args}}});
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{name}} returned value" + exception_result);{{/exception}}
{{/is_generic}}
{{#is_string_list}}
return MarshalStringArray({{c_name}}({{nativePtr}}{{c_args}}));
{{/is_string_list}}
{{#is_class_list}}
return MarshalBctbxList<{{{list_type}}}>({{c_name}}({{nativePtr}}{{c_args}}));
{{/is_class_list}}
}
{{/impl}}
{{/has_impl}}
{{/dllImports}}
}
{{/_class}}
{{/classes}}
#endregion
}