mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-18 11:38:08 +00:00
547 lines
16 KiB
Text
547 lines
16 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);
|
|
#if WINDOWS_UWP
|
|
belle_sip_object_data_set(ptr, "cs_obj", objPtr, IntPtr.Zero);
|
|
#else
|
|
belle_sip_object_data_set(ptr, "cs_obj", objPtr, null);
|
|
#endif
|
|
|
|
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}}
|
|
|
|
/// Get the native window handle of the video window, casted as an unsigned long.
|
|
public string NativeVideoWindowIdString
|
|
{
|
|
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}}
|
|
|
|
/// Get the native window handle of the video window.
|
|
public string NativeVideoWindowIdString
|
|
{
|
|
get
|
|
{
|
|
return Marshal.PtrToStringUni(linphone_core_get_native_video_window_id(nativePtr));
|
|
}
|
|
set
|
|
{
|
|
linphone_core_set_native_video_window_id(nativePtr, Marshal.StringToHGlobalUni(value));
|
|
}
|
|
}
|
|
|
|
/// Get the native window handle of the video preview window.
|
|
public string NativePreviewWindowIdString
|
|
{
|
|
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 ? (char)1 : (char)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}}) == (char)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
|
|
}
|