How to close pjsip correctly when application needs to exit

comments

I just wrote an answer on stackoverflow and I think that it is worth to put it here too.

From my expirience of working with PJSUA2, the correct way to exit is to ensure that destructors of all calls are called before pj::Account destructor and desturctor for pj::Account is called before pj::Endpoint destructor.

In my applications I have integer calls counter and exit bool flag in pj::Account derived class like:

class MyAccount : public pj::Account
{
public:
    ...
    void incrementCallsCount() { ++_callsCount; }
    void decrementCallsCount() { --_callsCount; }
    size_t getCallsCount() const { return _callsCount; }
    ...
    void setWantExit(bool wantExitFlag) { _wantExitFlag = wantExitFlag; }
    void onIncomingCall(pj::OnIncomingCallParam &prm)
    {
       if (_wantExitFlag)
           return;
       MyCall *call = MyCall::create(*this, prm.callId);
       // Do your stuff with call:
       // - add to map id->call
       // - answer SIP 180 Ringing / SIP 200 OK
    }
    ...
private:
    std::atomic<size_t> _callsCount;
    bool _wantExitFlag;
};

In constructor of pj::Call derived class I call incrementCallsCount() and in destructor I call decrementCallsCount() like:

class MyCall : public pj::Call
{
public:
    typedef pj::Call base_class;
    static MyCall *create(MyAccount &account, int callId)
    {
        return new MyCall(account, callId);
    }

    virtual void onCallState(pj::OnCallStateParam& prm)
    {
        pj::CallInfo ci = getInfo();
        if (ci.state == PJSIP_INV_STATE_DISCONNECTED)
        {
            // You may call some onDisconnected() handler function here
            delete this;
            return;
        }
    }
    ...
private:
    MyCall(MyAccount &account, int callId)
        : base_class(account, callId)
        , _myAccount(account)
    {
        _myAccount.incrementCallsCount();
    }

    virtual ~MyCall()
    {
        _myAccount.decrementCallsCount();
    }

    MyAccount &_myAccount;
};

Note that constructor and destructor declared as private, to ensure that users create calls by static fuction MyCall::create() only! MyCall class takes responsibility for memory management: call deleted only when PJSUA2 tells to delete call (PJSIP_INV_STATE_DISCONNECTED call state).

With this functions and classes in mind, if you just want to exit from application almost immediately, you should:

  • Stop creating MyCall in MyAccount by _myAccount.setWantExit(true). When pj::Call::onIncomingCall() function returns immediately, PJSUA2 hande this by executing hangup() for the call immediately.

  • call Endpoint::instance().hangupAllCalls()

  • wait until MyAccount::getCallsCount() will return 0

  • ensure MyAccount's destructor is called before Enpoint's destructor

  • exit application

Comments