Integration guide
Windows
Library distributive
Siprix SDK for Windows distributed as single .zip archive. It contains following folders/files:
include:
Siprix.h. Header file. Using in the include setting when integrating library into C++ applications.
lib:
siprix.lib. Library file. Using in the linking settings when integrating library into C++ applications.
siprix.dll. Binary file with API and signalling implementation for x86_64.
siprixMedia.dll. Binary file with media implementation for x86_64.
Deploy to users computers
Library doesn’t require any specific steps for deploying (like register it as ActiveX, etc).
Just copy siprix.dll and siprixMedia.dll along with application’s executable file(s).
Integration into C++ application
Modify project’s include settings with path to library’s folder
includeModify project’s link settings with path to library’s
lib\siprix.libModify code:
Add library initialization code;
Implement adding accounts and making calls;
Add own model implementation;
See also example application SiprixUA
Integration into C# application
Copy binary files.
These 2 files:
siprix.dllandsiprixMedia.dllhas to be present in the folder with compiled application. Possible ways of adding them:Copy source files.
Copy API and Model files
SiprixAPI.cs,SiprixModels.csfrom example application SampleWPFModify code:
If library is adding to WinForms project comment first line in the models file
#define WPF_PROJECTRedesign
Siprix.ObjModel::loadSavedAccountsandSiprix.ObjModel::postSaveAccountsChangeswith own property or own code of saving/loading accounts state;Redesign LogsModel, member variable
Siprix.ObjModel.logsModel_.If logging not required - don’t create instance of it, just set to null.
If it’s nice to have - replace implementation of the LogsModel::Print with own code.
If application needs to display logs on UI - use as is.
Add library initialization code when main window loaded (or when dialer required)
invoke
SiprixModel.Instance.Initialize(App.Current.Dispatcher);in WPF prject.invoke
SiprixModel.Instance.Initialize(control);- in WinForms project, wherecontrolargument means any control or main window.
Add library cleanup code when main window closed (or dialer not required)
invoke
SiprixModel.Instance.UnInitialize();.
Add other code which invokes
AddAccount,Invite,Accept, etc., and handles model changes.
Render video in Windows application
Library renders video on the window, specified by its HWND handle.
When it’s WinForms application implementation is straightforward as each control has property .Handle,
which can be used as argument of method Call_SetVideoWindow().
In case of WPF application implementation is a bit more complicated and requires to use HwndHost or other approach of hosting Win32 control.
If using Win32 controls is not an option library provides ability to add own renderer, which can handle raw frames, see Call_SetVideoRenderer().
It’s planning to add support of WriteableBitmap to the example application: //TODO
If you have more questions/ideas contact: support@siprix-voip.com.
Android
Library distributive
Siprix SDK for Android distributed as single .aar file. It contains compiled java code and native binaries for platforms: arm64-v8a, armeabi-v7a, x86, x86_64.
Recommended project structure
UI part
Represents MainActivity, fragments, controls.
Asks runtime permissions, required by library.
Displays state of the object model.
Invokes methods of the object model.
Service part
Aggregates object model.
Continues working when UI destroyed/recreating.
Displays notifications/starts activity when incoming call received.
Siprix object model
Aggregates library instance.
Handles library events and raises signals for updating UI.
Contains cumulative state of the dialer (accounts/calls/.. details + ability to serialize it).
See also Object diagram
This approach is one of many possible and can be extended/modified/improved… by the developer(s) who will integrate library and knows more details about particular application’s requirements and existing implementation.
Integration into existing project
Copy aar file to the folder:
<Project>/app/libsModify build.gradle
... dependencies { ... implementation(files("libs/siprix_voip_sdk.aar")) ... }
Add the following permission to manifest
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-permission android:name="android.permission.CAMERA" android:required="false"/> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.VIBRATE" /> <!-- Required if application will start foreground service --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" /> <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- Required if application will received incoming calls in background --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
Add code which asks runtime permissions:
RECORD_AUDIO- required always.CAMERA- required only if application needs to send video from local camera.POST_NOTIFICATIONS- required when application will displays notifications about received incoming calls.
Copy model files
Copy folder model from example application SampleJava.
Set actual package name
package <...>.model;in each copied file.If required push notifications support set
kFcmPushNotifEnabled = truein the ObjModel.java:44 and also check code of sending push token in methodappendPushTokenToAccountin the AccountsModel.java:69.If required - convert copied files to kotlin.
Add service implementation
Copy CallNotifService.java from example application SampleJava.
Set actual package name
package <...>;Set actual import
import <...>.model.ObjModel;Review code of creating notifications, modify it if required.
Declare service in the manifest as shown below. Highlighted line (along with FOREGROUND* permissions, shown on step [3] above) required only if application will start this service in foreground mode.
<service android:name=".CallNotifService" android:exported="false" android:stopWithTask="false" android:foregroundServiceType="phoneCall" />
Update MainActivity
Copy from example application SampleJava:
Members:
ObjModel objModel_andCallNotifService bgService_.Method
startAndBindBgServiceand invoke it fromonCreate.Implementation
ServiceConnection serviceConnection_ = ....LaunchMode of the activity
android:launchMode="singleTop"from the manifest. This launch mode required to prevent creating few instances of same activity when it started by user/service.
Add own implementation
As tutorial could be used the following approach:
Add to the activity 2 buttons and 2 labels
Copy methods from code fragment below. It adds account/call, assigns model observers and displays update of the states on the text labels.
Assign copied methods as click event handlers of the added buttons. [!] Don’t forget to review this code and update hardcoded SIP account credentials and phone numbers.
For final test:
Build app, run on device or emulator.
Click [AddAccount] - it should add account and display registration status.
Click [AddCall] - it should make outgoing call using account, from previous step.
public void onAddCallButtonClick() { try { if(objModel_.accounts_.size()==0) return; DestModel dest = new DestModel(); dest.setToExt("1012"); dest.setSrcAccId(objModel_.accounts_.get(0).getAccId()); objModel_.calls_.invite(dest); objModel_.calls_.setObserver(new ModelObserver() { @Override public void onModelChanged() { if(objModel_.calls_.size() > 0) { CallModel call = objModel_.calls_.get(0); callStateLabel.setText(call.getState().toString()); }else{ callStateLabel.setText("No calls"); } } }); }catch (Exception e) { Toast.makeText(this, e.getMessage(),Toast.LENGTH_SHORT).show(); } } public void onAddAccountButtonClick() { try{ AccountModel acc = new AccountModel(); acc.setSipServer("192.168.0.122"); acc.setSipExtension("1019"); acc.setSipPassword("12345"); acc.setExpireTime(300); objModel_.accounts_.add(acc); objModel_.accounts_.setObserver(new ModelObserver() { @Override public void onModelChanged() { AccountModel acc = objModel_.accounts_.get(0); accStateLabel.setText(acc.getRegText()); } }); }catch(Exception e) { Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); } }
Note
When application will start next time it restores account, saved by the model in the previous session. Final implementation should take it into account and assign model observer just after start.
Render video in Android application
Library provides its own class SiprixVideoRenderer inherited from SurfaceView.
Application should create instance of this class and assign it for selected call
by invoking callSetVideoRenderer(callId, renderer);
Here is example of declaration renderer in the layout resource file:
<com.siprix.SiprixVideoRenderer android:id="@+id/remote_renderer" android:layout_width="130dp" android:layout_height="100dp" android:elevation="-1dp" android:visibility="visible"/>
See also: Working in background.
MacOS
Library distributive
Siprix SDK for MacOS distributed as 2 frameworks: siprix.framework and siprixMedia.framework.
They contain binaries for platforms: x86_64 and arm64.
Also siprix.framework contains headers:
Siprix.h. ObjC header file. Using for integrating library into ObjC/Swift applications.
SiprixCpp.h. C++ header file. Using for integrating library into C/C++ applications.
Integration into existing project
Copy
siprix.frameworkandsiprixMedia.frameworkto project’s folder.Set embed settings
In Xcode, select build target, then select “General” tab, scroll down to “Framework, Libraries, and Embedded Content”, select “+”, then browse and select copied frameworks.
Request authorization for audio/video capture and network.
In Xcode, select build target, then select
Infotab, add NSMicrophoneUsageDescription key, if required video calls add also NSCameraUsageDescription key.Then select
Signing & Capabilitiestab, in the App Sandbox section check Network, Camera, Audio Input.Copy model file
Copy
SiprixModels.swiftfrom example application SampleSwiftUI.Add copied file to XCode project by clicking menu Add Files to <Project>.
If LogsModel not required set it nil on line 818:
logs = nil;//LogsModel()of the copied model file.
Initialize/uninitialize library
Add following initialization code to the
Appclass.@main struct VoipTestApp: App { ... class AppDelegate: NSObject, NSApplicationDelegate { func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool{ SiprixModel.shared.uninitialize() return true } } init() { ... SiprixModel.shared.initialize() ... } @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { ContentView() } }
Add own implementation
As tutorial could be used code below, which builds SwiftUI View with ability to add account, make call, display status.

struct ContentView: View { @StateObject var accList = SiprixModel.shared.accountsListModel @StateObject var callsList = SiprixModel.shared.callsListModel @State private var addAlert = false @State private var addErr = "" var body: some View { HStack { VStack { Button(action: addAcc) { Text("Add account") Image(systemName: "text.badge.plus").font(.body) } ScrollView { ForEach(accList.accounts) { acc in HStack { Text(acc.name) regStateImg(acc) } } }.border(.gray) } VStack { Button(action: addCall) { Text("Add call") Image(systemName: "phone.badge.plus.fill").font(.body) } ScrollView{ ForEach(callsList.calls) { call in HStack { Text(call.remoteSide) Text(call.stateStr) Button(action: { call.bye() }) { Text("Hangup") } } } }.border(.gray) } } .alert("Can't add", isPresented: $addAlert) {} message: { Text(addErr) } } private func addAcc() { let accData = SiprixAccData() accData.sipServer = "192.168.0.122" accData.sipExtension = "1018" accData.sipPassword = "12345" accData.expireTime = 300 let errCode = accList.add(accData) if(errCode != kErrorCodeEOK) { addErr = SiprixModel.shared.getErrorText(errCode) addAlert = true } } private func addCall() { let dest = SiprixDestData() dest.toExt = "1012" dest.fromAccId = Int32(accList.selectedAccId) let errCode = callsList.invite(dest) if(errCode != kErrorCodeEOK) { addErr = SiprixModel.shared.getErrorText(errCode) addAlert = true } } func regStateImg(_ acc: AccountModel) -> some View { switch acc.regState { case .success: Image(systemName: "checkmark.icloud") case .failed: Image(systemName: "xmark.icloud") case .removed: Image(systemName: "checkmark") default: Image(systemName: "arrow.clockwise.icloud") } } }
Render video in MacOS application
Library has special method: -(NSView* _Nonnull)createVideoWindow; for creating video windows.
Application should invoke this method, move created window to proper location and assign it to selected call
by invoking callSetVideoWindow(callId, wnd).
In case of using SwiftUI - create UIViewRepresentable as shown below
struct SiprixVideoView: UIViewRepresentable {
private var call : CallModel
private let isPreview : Bool
init(_ call: CallModel, isPreview : Bool) {
self.call = call
self.isPreview = isPreview
}
func makeUIView(context: Context) -> UIView {
let view = SiprixModel.shared.createVideoView()
call.setVideoView(view, isPreview:isPreview)
return view
}
func updateUIView(_ uiView: UIView, context: Context) { }
}
...
var body: some View {
ZStack(alignment: .bottomTrailing) {
if(call.withVideo) {
SiprixVideoView(call, isPreview:false)
SiprixVideoView(call, isPreview:true)
...
}
...
See more: UIViewRepresentable.
iOS
Library distributive
Siprix SDK for iOS distributed as 2 frameworks: siprix.xcframework and siprixMedia.xcframework.
They contain binaries for device (arm64) and also simulator (x86_64 and arm64).
Integration into existing project
Copy
siprix.xcframeworkandsiprixMedia.xcframeworkto project’s folder.Set embed settings
In Xcode, select build target, then select “General” tab, scroll down to “Framework, Libraries, and Embedded Content”, select “+”, then browse and select copied frameworks.
Request authorization for audio/video capture.
In Xcode, select build target, then select
Infotab, add NSMicrophoneUsageDescription key, if required video calls add also NSCameraUsageDescription key.See more: Requesting authorization to capture and save media.
Select checkbox Voice over IP in the signing and capabilities
In Xcode, select build target, then select
Signing & Capabilitiestab, add select checkbox Voice over IP.Copy model file
Copy
SiprixModels.swiftfrom example application SampleSwiftUI.Add copied file to XCode project by clicking menu Add Files to <Project>.
If LogsModel not required set it nil on line 818:
logs = nil;//LogsModel()of the copied model file.
Initialize library
Add following initialization code to the
Appclass.init() { ... SiprixModel.shared.initialize() ... }
Add own implementation
As tutorial could be used code below (same as for MacOS), which builds SwiftUI View with ability to add account, make call, display status.
struct ContentView: View { @StateObject var accList = SiprixModel.shared.accountsListModel @StateObject var callsList = SiprixModel.shared.callsListModel @State private var addAlert = false @State private var addErr = "" var body: some View { HStack { VStack { Button(action: addAcc) { Text("Add account") Image(systemName: "text.badge.plus").font(.body) } ScrollView { ForEach(accList.accounts) { acc in HStack { Text(acc.name) regStateImg(acc) } } }.border(.gray) } VStack { Button(action: addCall) { Text("Add call") Image(systemName: "phone.badge.plus.fill").font(.body) } ScrollView{ ForEach(callsList.calls) { call in HStack { Text(call.remoteSide) Text(call.stateStr) Button(action: { call.bye() }) { Text("Hangup") } } } }.border(.gray) } } .alert("Can't add", isPresented: $addAlert) {} message: { Text(addErr) } } private func addAcc() { let accData = SiprixAccData() accData.sipServer = "192.168.0.122" accData.sipExtension = "1018" accData.sipPassword = "12345" accData.expireTime = 300 let errCode = accList.add(accData) if(errCode != kErrorCodeEOK) { addErr = SiprixModel.shared.getErrorText(errCode) addAlert = true } } private func addCall() { let dest = SiprixDestData() dest.toExt = "1012" dest.fromAccId = Int32(accList.selectedAccId) let errCode = callsList.invite(dest) if(errCode != kErrorCodeEOK) { addErr = SiprixModel.shared.getErrorText(errCode) addAlert = true } } func regStateImg(_ acc: AccountModel) -> some View { switch acc.regState { case .success: Image(systemName: "checkmark.icloud") case .failed: Image(systemName: "xmark.icloud") case .removed: Image(systemName: "checkmark") default: Image(systemName: "arrow.clockwise.icloud") } } }
Render video in iOS application
Library has special method: -(UIView* _Nonnull)createVideoWindow; for creating video windows.
Approach is the same as explained above: Render video in MacOS application.
CallKit integration
Siprix provides source code of the model with ready to use CallKit implementation.
It’s available in SiprixModels.swift as part of example application SampleSwiftUI.
Model hides internal details and application can simply invoke methods like call.hold() or call.sendDtmf() or call.bye(). If CallKit enabled - these methods will trigger CX*Action’s, process them and perform SIP actions.
See also: CallKit-PushKit iOS.
Linux
Library distributive
Siprix SDK for Linux distributed as single .zip archive.
It contains following folders/files:
include:
Siprix.h. Header file. Using in the include setting when integrating library into C++ applications.
lib:
libsiprix.so. Binary file with API and signalling implementation for x86_64.
libsiprixMedia.so. Binary file with media implementation for x86_64.
Integration into C++ application
Modify project’s include settings with path to library’s folder
includeModify project’s link settings with path to library’s folder
libModify code:
Add library initialization code;
Implement adding accounts and making calls;
Add own model implementation;
See also example application SiprixUA.







