Guido
Guido

Reputation: 319

Unable to do two calls and conference with Python PJSIP

I'm trying to do a conference call between 2 asterisk extension, managed by pjsip. I want to call 123 and 124, and make them to talk.

I've set up two different transports and two accounts, this is not mandatory but it's the way I'm trying. To use a single account for both calls would be good anyway.

Problem is that the following code:

import pjsua
import threading
from time import sleep


def log_cb(level, str, len):
    print str,


class MyAccountCallback(pjsua.AccountCallback):
    sem = None

    def __init__(self, account=None):
        pjsua.AccountCallback.__init__(self, account)

    def wait(self):
        self.sem = threading.Semaphore(0)
        self.sem.acquire()

    def on_reg_state(self):
        if self.sem:
            if self.account.info().reg_status >= 200:
                self.sem.release()


def cb_func(pid) :
    print '%s playback is done' % pid
    current_call.hangup()


# Callback to receive events from Call
class MyCallCallback(pjsua.CallCallback):

    def __init__(self, call=None, dostuff=True):
        pjsua.CallCallback.__init__(self, call)
        self.dostuff=dostuff

    # Notification when call state has changed
    def on_state(self):
        if not self.dostuff:
            return

        global current_call
        global in_call
        print "Call with", self.call.info().remote_uri,
        print "is", self.call.info().state_text,
        print "last code =", self.call.info().last_code, 
        print "(" + self.call.info().last_reason + ")"


        #if self.call.info().media_state == pjsua.MediaState.ACTIVE:
        #    # Connect the call to sound device
        #    call_slot = self.call.info().conf_slot
        #    lib.conf_connect(call_slot, 0)
        #    lib.conf_connect(0, call_slot)
        #    print "Hello world, I can talk!"

        if self.call.info().state == pjsua.CallState.DISCONNECTED:
            current_call = None
            print 'Current call is', current_call

            in_call = False
        elif self.call.info().state == pjsua.CallState.CONFIRMED:
            print "Call Answred"
            another_call = make_call(acc2, dst_uri2, dostuff=False)
            conf_slot = self.call.info().conf_slot
            conf_slot_2 = another_call.info().conf_slot
            i = 0
            while i < 10:
                print '#####################################'
                print '#####################################'
                print 'conf_slot ' + str(conf_slot)
                print 'conf_slot_2 ' + str(conf_slot_2)
                print '#####################################'
                print '#####################################'
                if another_call.info().state == pjsua.CallState.CONFIRMED:
                    i = pjsua.Lib.instance()
                    i.conf_connect(conf_slot, conf_slot_2)
                    i.conf_connect(conf_slot_2, conf_slot)
                else:
                    print '#####################################'
                    print 'FIRST CALL STATE %s' % self.call.info().__dict__
                    print '\n\n'
                    print 'ANOTHER CALL STATE %s' % another_call.info().__dict__
                    print '#####################################'
                    sleep(2)
                    i += 2

            sleep(25)
            self.call.hangup()
            another_call.hangup()
            in_call = False

    # Notification when call's media state has changed.
    def on_media_state(self):
        if self.call.info().media_state == pjsua.MediaState.ACTIVE:
            print "Media is now active"
        else:
            print "Media is inactive"


# Function to make call
def make_call(ac, uri, dostuff=True):
    try:
        print "Making call to", uri
        return ac.make_call(uri, cb=MyCallCallback(dostuff=dostuff))
    except pjsua.Error, e:
        print "Exception: " + str(e)
        return None


lib = pjsua.Lib()

try:
    cfg = pjsua.MediaConfig()
    lib.init(log_cfg = pjsua.LogConfig(level=4, callback=log_cb), media_cfg=cfg)
    t1 = lib.create_transport(pjsua.TransportType.UDP, pjsua.TransportConfig(5081))
    t2 = lib.create_transport(pjsua.TransportType.UDP, pjsua.TransportConfig(5082))
    lib.set_null_snd_dev()
    lib.start()
    lib.handle_events()

    acc_cfg = pjsua.AccountConfig()
    acc_cfg.id = "sip:11111"
    acc_cfg.reg_uri = "sip:localhost"
    #acc_cfg.proxy = [ "sip:PROXY.YOURSIPSERVER.COM;lr" ]
    acc_cfg.auth_cred = [ pjsua.AuthCred("*", "11111", "secret")]


    acc_cb = MyAccountCallback()
    acc = lib.create_account(acc_cfg, cb=acc_cb)
    acc.set_transport(pjsua.Transport(lib, 1))

    acc_cb.wait()

    print "\n"
    print "Registration complete, status=", acc.info().reg_status, \
          "(" + acc.info().reg_reason + ")"


    ##########
    # ACCO 2
    ##########

    acc2_cfg = pjsua.AccountConfig()
    acc2_cfg.id = "sip:11112"
    acc2_cfg.reg_uri = "sip:localhost"
    acc2_cfg.transport_id = t2._id
    # a2cc_cfg.proxy = [ "sip:PROXY.YOURSIPSERVER.COM;lr" ]
    acc2_cfg.auth_cred = [pjsua.AuthCred("*", "11112", "secret")]
    acc2_cb = MyAccountCallback()
    acc2 = lib.create_account(acc2_cfg, cb=acc2_cb)
    acc2.set_transport(t2)
    acc2_cb.wait()
    ###########


    #YOURDESTINATION is landline or mobile number you want to call
    dst_uri = "sip:123@localhost"
    dst_uri2 = "sip:124@localhost"

    in_call = True
    lck = lib.auto_lock()
    current_call = make_call(acc, dst_uri)
    print 'Current call is', current_call
    del lck

    #wait for the call to end before shuting down
    while in_call:
        print('In call')
        sleep(3)
        pass
    #sys.stdin.readline()
    lib.destroy()
    lib = None

except pjsua.Error, e:
    print "Exception: " + str(e)
    lib.destroy()

Produce the following result:

#####################################
In call
#####################################
#####################################
conf_slot 1
conf_slot_2 -1
#####################################
#####################################
#####################################
FIRST CALL STATE {'total_time': 6, 'account': <pjsua.Account instance at 0x7f9482f90ea8>, 'conf_slot': 1, 'sip_call_id': 'de7fe2e7-21c5-4763-a02b-a7a08ab20d02', 'uri': 'sip:11111', 'media_state': 1, 'last_reason': 'OK', 'remote_contact': '<sip:[email protected]:5060>', 'state': 5, 'contact': '<sip:127.0.0.1:5081;ob>', 'role': 0, 'state_text': 'CONFIRMED', 'media_dir': 3, 'remote_uri': 'sip:123@localhost', 'call_time': 6, 'last_code': 200}



ANOTHER CALL STATE {'total_time': 6, 'account': <pjsua.Account instance at 0x7f9482fa0200>, 'conf_slot': -1, 'sip_call_id': '094b998a-2b0c-42eb-b5ac-0a44251a6566', 'uri': 'sip:11112', 'media_state': 0, 'last_reason': '', 'remote_contact': '', 'state': 1, 'contact': '<sip:127.0.0.1:5082;ob>', 'role': 0, 'state_text': 'CALLING', 'media_dir': 0, 'remote_uri': 'sip:124@localhost', 'call_time': 0, 'last_code': 0}
#####################################

And the second call doesn't start. As it doesn't, I think the conf_slot is still -1, and it's so impossible to do the bridge:

i.conf_connect(conf_slot, conf_slot_2)
i.conf_connect(conf_slot_2, conf_slot)

Any hint would be very appreciated.

Upvotes: 1

Views: 894

Answers (1)

vgonisanz
vgonisanz

Reputation: 11930

It seems that your second call is not established. You have a lot of code mixed. I will recomend you to try to get a call first working, using an external SIP client (in example empathy (https://en.wikipedia.org/wiki/Empathy_(software) + SIP plugin)

When you make work to get an incoming call with the conference bridge, then try to use 2 threads to manage 2 different endpoints. If a pjsip callback is busy (you use it until a long task end) other callbacks won't trigger so it is impossible to make it work.

Try to isolate Call/Account code creating custom classes and call from different threads.

Upvotes: 1

Related Questions