Flow Group SASFlow Group
L'erp des Processus Relationnels
Systeme d'Information – Audit Industriel
> Home > Expertise & Knowledge > Technical Articles


Using sipXtapi with .Net

lire la version francophone Version française

Defining the Interop class
Interop with the call callback
Some useful links...

The sipXtapi SDK is a C application programming interface for voice communications over IP. Specifically, sipXtapi provides a generalized telephony interface on top of the Session Initiation Protocol (SIP), RFC 3261, and the real-time Transport Protocol (RTP), RFC 1889.

While the SIP and RTP protocols provide signaling and media transport infrastructure, sipXtapi also includes many other protocol and standards implementations needed for voice communications.

Defining the Interop class

The definition of the enums and the encapsultation of the methods is not really a problem:

using System; using System.Runtime.InteropServices; namespace sipXtapi.Interop { /// <summary> /// /// </summary>public enum SIPX_RESULT : int { SIPX_RESULT_SUCCESS = 0, // Success SIPX_RESULT_FAILURE, // Generic Failure SIPX_RESULT_NOT_IMPLEMENTED, // Method/API not implemented SIPX_RESULT_OUT_OF_MEMORY, // Unable to allocate enough memory // to perform operation SIPX_RESULT_INVALID_ARGS, // Invalid arguments; bad handle, // argument out of range, etc. SIPX_RESULT_BAD_ADDRESS, // Invalid SIP address SIPX_RESULT_OUT_OF_RESOURCES, // Out of resources } /// <summary> /// /// </summary>public enum SIPX_LOG_LEVEL : int { LOG_LEVEL_DEBUG = 0, ///< debug-level messages LOG_LEVEL_INFO, ///< informational messages LOG_LEVEL_NOTICE, ///< normal, but significant, /// conditions LOG_LEVEL_WARNING, ///< warning conditions LOG_LEVEL_ERR, ///< error conditions LOG_LEVEL_CRIT, ///< critical conditions LOG_LEVEL_ALERT, ///< action must be taken /// immediately LOG_LEVEL_EMERG, ///< system is unusable } ... /// <summary> /// /// </summary>public sealed class sipXtapi { private const string DLLNAME = "sipXtapi.dll"; // Default UDP portpublic const int DEFAULT_UDP_PORT = 5060; ... // Bind to all interfacespublic const string DEFAULT_BIND_ADDRESS = ""; private sipXtapi() { } /// <summary> /// /// </summary> /// <param name="result"></param> public static void CheckResult(SIPX_RESULT result) { if (result == SIPX_RESULT.SIPX_RESULT_SUCCESS) return;throw new sipXtapi.SIPException(result); } [DllImport(DLLNAME)] public static extern SIPX_RESULT sipxInitialize(ref IntPtr instance, int udpPort, int tcpPort, int tlsPort, int rtpPortStart, int maxConnections, string identity, string szBindToAddr); [DllImport(DLLNAME)] public static extern SIPX_RESULT sipxUnInitialize(IntPtr instance); ... } }

Interop with the call callback

This is the tricky part. The callbacks are called using the C convention, while it is not possible to use an attribute to modify it on the invoke method of the delegate.

So, what could be done is to declare the callback delegate in a separate file, which will be compiled in a separate assembly.

using System;namespace sipXtapi.Interop.Delegates { public delegate void EventCallBackDelegate(UInt32 hCall, UInt32 hLine, Int32 eMajor, Int32 eMinor, IntPtr userData); public delegate void LineCallBackDelegate(UInt32 hLine, Int32 eMajor, IntPtr userData); }

Then, you have to compile the file and desassemble it:

c:\sipXtapi.net>csc /target:library sipXtapi.delegates.cs¶
c:\sipXtapi.net>ildasm /all sipXtapi.delegates.dll /out=sipXtapi.delegate
// WARNING: Created Win32 resource file sipXtapi.delegates.res¶

Now, edit the IL file and add the calling convention in front of the invoke methods:

.namespace sipXtapi.Interop.Delegates { .class /*02000002*/ public auto ansi sealed EventCallBackDelegate extends [mscorlib/* 23000001 */]System.MulticastDelegate/* 01000001 */ { .method /*06000001*/ public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed // SIG: 20 02 01 1C 18 { } // end of method EventCallBackDelegate::.ctor .method /*06000002*/ public hidebysig virtual instance void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) Invoke(unsigned int32 hCall, unsigned int32 hLine, int32 eMajor, int32 eMinor, native int userData) runtime managed // SIG: 20 05 01 09 09 08 08 18 { } // end of method EventCallBackDelegate::Invoke ... }

Finally, re-assemble the file:

c:\sipXtapi.net>ilasm /dll /quiet sipXtapi.delegates.il¶
Assembling 'sipXtapi.delegates.il' , no listing file, to DLL --> 'sipXtap
Source file is ANSI¶
Operation completed successfully¶
For your information

You do not have to declare the callbacks in a separate file. It is just more convenient because that way, you do not have to redo manually those steps whenever you add an interop method.

Some useful links...

all the informations here are provided as is, without any warranty of any kind.
© 2022 Flow Group SAS - Flow Group est une marque déposée de GL Conseil SA.