The Endpoint

The pj::Endpoint class is a singleton class, and application MUST create this class instance before it can do anything else, and similarly, once this class is destroyed, application must NOT call any library API. This class is the core class of PJSUA2, and it provides the following functions:

  • Starting up and shutting down

  • Customization of configurations, such as core UA (User Agent) SIP configuration, media configuration, and logging configuration

This chapter will describe the functions above.

Instantiating the endpoint

Before anything else, you must instantiate the Endpoint class:

Endpoint *ep = new Endpoint;

Once the endpoint is instantiated, you can retrieve the Endpoint instance using pj::Endpoint::instance() static method.

Creating the library

Create the library by calling its pj::Endpoint::libCreate() method:

try {
    ep->libCreate();
} catch(Error& err) {
    cout << "Startup error: " << err.info() << endl;
}

The libCreate() method will raise exception if error occurs, so we need to trap the exception using try/catch clause as above. See pj::Error for reference.

Initializing and configuring the library

The pj::EpConfig class provides endpoint configuration which allows the customization of the following settings:

  • pj::UAConfig, to specify core SIP user agent settings.

  • pj::MediaConfig, to specify various media global settings

  • pj::LogConfig, to customize logging settings.

Tip

Some settings can be specified on per account basis, in the pj::AccountConfig, when creating an pj::Account. Creating accounts will be explained in next section.

To customize the settings, create instance of EpConfig class and specify them during the endpoint initialization (will be explained more later), for example:

EpConfig ep_cfg;
ep_cfg.logConfig.level = 5;
ep_cfg.uaConfig.maxCalls = 4;
ep_cfg.mediaConfig.sndClockRate = 16000;

Next, you can initialize the library by calling pj::Endpoint::libInit():

try {
    EpConfig ep_cfg;
    // Specify customization of settings in ep_cfg
    ep->libInit(ep_cfg);
} catch(Error& err) {
    cout << "Initialization error: " << err.info() << endl;
}

The snippet above initializes the library with the default settings.

Creating one or more transports

Application needs to create one or more transports before it can send or receive SIP messages:

try {
    TransportConfig tcfg;
    tcfg.port = 5060;
    TransportId tid = ep->transportCreate(PJSIP_TRANSPORT_UDP, tcfg);
} catch(Error& err) {
    cout << "Transport creation error: " << err.info() << endl;
}

The pj::Endpoint::transportCreate() method returns the newly created Transport ID and it takes the transport type and pj::TransportConfig object to customize the transport settings like bound address and listening port number. Without this, by default the transport will be bound to INADDR_ANY and any available port.

There is no real use of the Transport ID, except to create userless account (with pj::Account::create(), as will be explained later), and perhaps to display the list of transports to user if the application wants it.

Starting the library

Now we’re ready to start the library. We need to start the library to finalize the initialization phase, e.g. to complete the initial STUN address resolution, initialize/start the sound device, etc. To start the library, call pj::Endpoint::libStart() method:

try {
    ep->libStart();
} catch(Error& err) {
    cout << "Startup error: " << err.info() << endl;
}

Shutting down the library

Once the application exits, the library needs to be shutdown so that resources can be released back to the operating system. Although this can be done by deleting the Endpoint instance, which will internally call pj::Endpoint::libDestroy(), it is better to call it manually because on Java or Python there are problems with garbage collection as explained earlier:

ep->libDestroy();
delete ep;