Writing a VoIP Application
SK400VOP exposes a small application-facing API and callback model so the surrounding product does not need to implement SIP signaling itself. The supplied demo application can be used as a structural reference for Windows and Linux integrations; the same sequence can be adapted to other operating systems, RTOS environments and OS-less targets.
Use the supplied headers and demo as the final reference. The examples below focus on integration sequence. Type definitions, callback signatures and configuration fields can differ between licensed releases.
1. Include the public headers
Application source files that use SK400VOP types or APIs should include the common definitions and public API header:
#include "common.h"
#include "ippapi.h"
2. Populate callback interfaces
Before initializing signaling, populate the configuration structure with the application callbacks used for signaling events, media handling and network access.
A representative setup is:
/* Signaling events delivered to the application. */
ippconf.sigCB.eventHandler = uiEventCallback;
/* Media integration. */
ippconf.mediaCB.mediaContextCreate =
(MEDIA_CONTEXT_CREATE_CB)mediaContextCreate;
ippconf.mediaCB.mediaContextDestroy =
(MEDIA_CONTEXT_DESTROY_CB)mediaContextDestroy;
ippconf.mediaCB.mediaSetFormat =
(MEDIA_SET_FORMAT_CB)mediaSetFormat;
ippconf.mediaCB.mediaDecodeAndRender =
(MEDIA_DECODE_AND_RENDER_CB)mediaDecodeAndRender;
ippconf.mediaCB.mediaCaptureAndEncode =
(MEDIA_CAPTURE_AND_ENCODE_CB)mediaCaptureAndEncode;
/* Network integration. */
ippconf.netCB.socketCreate = (SOCK_CREATE_CB)socket;
ippconf.netCB.socketClose = (SOCK_CLOSE_CB)closesocket;
ippconf.netCB.socketBind = (SOCK_BIND_CB)bind;
ippconf.netCB.socketSendTo = (SOCK_SENDTO_CB)sendto;
ippconf.netCB.socketReceiveFrom = (SOCK_RECEIVEFROM_CB)recvfrom;
ippconf.netCB.socketIoctl = (SOCK_IOCTL_CB)ioctlsocket;
ippconf.netCB.inetPToN = (INET_PTON_CB)inet_pton;
ippconf.netCB.inetNToP = (INET_NTOP_CB)inet_ntop;
ippconf.netCB.netMatchSubnet =
(NET_MATCH_SUBNET_CB)netMatchSubnet;
ippconf.netCB.netGetLocalAddr =
(NET_GET_LOCAL_ADDR_CB)netGetLocalAddr;
ippconf.netCB.netGetMappedAddr =
(NET_GET_MAPPED_ADDR_CB)netGetMappedAddr;
ippconf.netCB.netResolveHost =
(NET_RESOLVE_HOST_CB)netResolveHost;
The example above uses Windows socket names for close/control operations. On POSIX-like platforms, application wrappers commonly map the corresponding callbacks to close() and ioctl() instead.
3. Configure a SIP registry
After callbacks are installed, populate the SIP transport and registry fields required by the application.
ippconf.sipPortUDP = 5060;
ippconf.numRegistries = 1;
/* First registry: SIP. */
ippconf.registryInfo[0].protocol = SIG_PROTO_SIP;
strcpy(ippconf.registryInfo[0].username, "101");
strcpy(ippconf.registryInfo[0].password, "101");
strcpy(ippconf.registryInfo[0].context, "");
strcpy(ippconf.registryInfo[0].servername, "192.168.1.100");
ippconf.registryInfo[0].serverport = htons(5060);
ippconf.registryInfo[0].regRefreshTime = 0;
ippconf.registryInfo[0].status = REG_PENDING;
Port byte order
Older copies of this documentation used ntohs(5060) in the example. A literal such as 5060 starts in host byte order, so when the field requires network byte order the correct conversion is htons(5060).
If your SK400VOP release defines serverport in host byte order instead, assign the host-order value required by that release. Check the supplied header/demo before changing established application code.
Credential handling
The values above are deliberately simple documentation placeholders. Production applications should not hard-code real SIP credentials into source code. Load secrets from a protected configuration mechanism appropriate to the target platform and avoid logging them.
4. Initialize signaling
With the configuration populated, initialize the signaling module and request SIP support:
UInt32 err;
err = ippInitMessaging(&ippconf, SIG_PROTO_SIP);
if (err != ERR_OK) {
/* Handle initialization failure before continuing. */
}
Do not start registration or the signaling loop when initialization fails.
5. Add supported codecs
Add codecs in preference order. In the following example, A-law is preferred over µ-law because it is added first:
ippAddCodec(MT_AUDIO, PT_ALAW, 8000, 1, EN_ALAW);
ippAddCodec(MT_AUDIO, PT_ULAW, 8000, 1, EN_ULAW);
The application must provide matching media implementation through the configured media callbacks.
6. Register with the SIP server
The following call requests a 3600-second registration refresh interval:
printf("Registering with server...\n");
ippRegister(3600);
The reference integration treats registration as a blocking setup step and continues after configured registrations have completed with success or failure.
For deployments that intentionally do not register, configure the registry state according to the product's call-routing model rather than assuming registration is mandatory.
7. Start signaling
After initialization, codec setup and any required registration, start the signaling loop:
printf("Starting signaling...\n");
ippStartMessaging();
The reference implementation treats this as a long-running call. On a multitasking operating system, run it in a dedicated thread or task when the rest of the application must continue executing independently. In an OS-less integration, it can become the primary processing loop after startup.
8. Process asynchronous events
Incoming calls, ringback, call establishment, hangup and registration state changes are delivered through the configured signaling callback. Store the call context associated with each event and use it for subsequent operations on that call.
See Event Handlers for the event model and Signaling API for outgoing-call setup.
Integration checklist
Before considering a port complete, verify that:
- all required signaling, network and media callbacks are installed;
- callback return types and arguments match the headers for the licensed release;
- IPv4/IPv6 address structures use the expected byte order and family;
- SIP credentials are loaded securely rather than embedded in source;
- codec negotiation matches the codecs actually implemented by the media layer;
- call contexts are preserved correctly across asynchronous events;
- error returns from initialization and call setup are handled explicitly;
- the signaling loop runs in the execution context expected by the target platform.