[pjsip] simple wxpython gui for pjsua

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Dear all,

please find below a simple wxpython gui for pjsua. The only functionality is to make calls and to hang up. Really simple but it could help someone. 

Best regards,
Sergio

###########################################################
import wx
import py_pjsua
import sys
import thread

# Configurations
#
THIS_FILE = "pjsua_app.py"
C_QUIT = 0
C_LOG_LEVEL = 4

# STUN config.
# Set C_STUN_SRV to the address of the STUN server to enable STUN
#
C_STUN_SRV = ""
C_SIP_PORT = 5064
C_STUN_PORT = 3478


# Globals
#
g_ua_cfg = None
g_acc_id = py_pjsua.PJSUA_INVALID_ID
g_current_call = py_pjsua.PJSUA_INVALID_ID
g_wav_files = []
g_wav_id = 0
g_wav_port = 0
g_rec_file = ""
g_rec_id = 0
g_rec_port = 0




class Frame1(wx.Frame):
    # create a simple windows frame (sometimes called form)
    # pos=(ulcX,ulcY)  size=(width,height) in pixels
    
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, -1, title, pos=(150, 150), size=(450, 350))
        self.create_controls()

    def create_controls(self):
        #Horizontal sizer
        self.h_sizer = wx.BoxSizer(wx.HORIZONTAL)
        #Vertical sizer
        self.v_sizer = wx.BoxSizer(wx.VERTICAL)

        #Widget Creation
        #Create the static text widget and set the text
        self.text = wx.StaticText(self, label="Address:")
        #Create the Edit Field (or TextCtrl)
        self.edit = wx.TextCtrl(self, size=wx.Size(250, -1))
        #Create the button
        self.callbutton = wx.Button(self, label="Call")
        self.hangupbutton = wx.Button(self, label="Hang Up")
        self.quitbutton = wx.Button(self, label="Quit")
        #bind the button click to our press function
        self.callbutton.Bind(wx.EVT_BUTTON, self.on_callbutton_pressed)
        self.hangupbutton.Bind(wx.EVT_BUTTON, self.on_hangupbutton_pressed)
        self.quitbutton.Bind(wx.EVT_BUTTON, self.on_quitbutton_pressed)
           
        #Add to horizontal sizer
        #add the static text to the sizer, tell it not to resize
        self.h_sizer.Add(self.text, 0,)
        #Add 5 pixels between the static text and the edit
        self.h_sizer.AddSpacer((5,0))
        #Add Edit
        self.h_sizer.Add(self.edit, 1)

        #Add to the vertical sizer to create two rows
        self.v_sizer.Add(self.h_sizer, 0, wx.EXPAND)
        #Add button underneath
        self.v_sizer.Add(self.callbutton, 0)
        self.v_sizer.Add(self.hangupbutton, 0)
        self.v_sizer.Add(self.quitbutton, 0)

        #Set the sizer
        self.SetSizer(self.v_sizer)
        #Fit ourselves to the sizer
        self.v_sizer.Fit(self)
        #Set the Minumum size
        self.SetMinSize(self.v_sizer.GetMinSize())

    def on_quitbutton_pressed(self, evt):
        # event handler for the Quit button click or Exit menu item
        self.Close()
    def on_hangupbutton_pressed(self, evt):
        # event handler for the Quit button click or Exit menu item
        #if g_current_call != py_pjsua.PJSUA_INVALID_ID:
        py_pjsua.call_hangup(0, 603, None, None)
        #else:
            
           # print "No current call"

    def on_callbutton_pressed(self, evt):
        # event handler for the Message button click
        print "Using account ", g_acc_id
        print "Make call to SIP URL: ",
        url = self.edit.GetValue()
        print url

        # Initiate the call!
        status, call_id = py_pjsua.call_make_call(g_acc_id, url, 0, 0, None)
        print "CALL ID ",call_id
        print "******************"
        if status != 0:
            py_pjsua.perror(THIS_FILE, "Error making call", status)
        else:
            g_current_call = call_id
        print g_current_call
        print "******************"

        

class wxPyApp(wx.App):
    def OnInit(self):
        # set the title too
        frame = Frame1(None, "Softphone")
        self.SetTopWindow(frame)
        frame.Show(True)
        #
        # main
        #
        app_init()
        app_start()
        return True


# Utility: display PJ error and exit
#
def err_exit(title, rc):
    py_pjsua.perror(THIS_FILE, title, rc)
    exit(1)


# Logging function (also callback, called by pjsua-lib)
#
def log_cb(level, str, len):
    if level <= C_LOG_LEVEL:
        print str,

def write_log(level, str):
    log_cb(level, str + "\n", 0)


# Utility to get call info
#
def call_name(call_id):
    ci = py_pjsua.call_get_info(call_id)
    return "[Call " + `call_id` + " " + ci.remote_info + "]"

# Callback when call state has changed.
#
def on_call_state(call_id, e):  
    global g_current_call
    ci = py_pjsua.call_get_info(call_id)
    write_log(3, call_name(call_id) + " state = " + `ci.state_text`)
    if ci.state == py_pjsua.PJSIP_INV_STATE_DISCONNECTED:
        g_current_call = py_pjsua.PJSUA_INVALID_ID

# Callback for incoming call
#
def on_incoming_call(acc_id, call_id, rdata):
    global g_current_call
    
    if g_current_call != py_pjsua.PJSUA_INVALID_ID:
        # There's call in progress - answer Busy
        py_pjsua.call_answer(call_id, 486, None, None)
        return
    
    g_current_call = call_id
    ci = py_pjsua.call_get_info(call_id)
    write_log(3, "*** Incoming call: " + call_name(call_id) + "***")
    write_log(3, "*** Press a to answer or h to hangup  ***")
    
    
    
# Callback when media state has changed (e.g. established or terminated)
#
def on_call_media_state(call_id):
    ci = py_pjsua.call_get_info(call_id)
    if ci.media_status == py_pjsua.PJSUA_CALL_MEDIA_ACTIVE:
        py_pjsua.conf_connect(ci.conf_slot, 0)
        py_pjsua.conf_connect(0, ci.conf_slot)
        write_log(3, call_name(call_id) + ": media is active")
    else:
        write_log(3, call_name(call_id) + ": media is inactive")


# Callback when account registration state has changed
#
def on_reg_state(acc_id):
    acc_info = py_pjsua.acc_get_info(acc_id)
    if acc_info.has_registration != 0:
        cmd = "registration"
    else:
        cmd = "unregistration"
    if acc_info.status != 0 and acc_info.status != 200:
        write_log(3, "Account " + cmd + " failed: rc=" + `acc_info.status` + " " + acc_info.status_text)
    else:
        write_log(3, "Account " + cmd + " success")


# Callback when buddy's presence state has changed
#
def on_buddy_state(buddy_id):
    write_log(3, "On Buddy state called")
    buddy_info = py_pjsua.buddy_get_info(buddy_id)
    if buddy_info.status != 0 and buddy_info.status != 200:
        write_log(3, "Status of " + `buddy_info.uri` + " is " + `buddy_info.status_text`)
    else:
        write_log(3, "Status : " + `buddy_info.status`)

# Callback on incoming pager (MESSAGE)
#       
def on_pager(call_id, strfrom, strto, contact, mime_type, text):
    write_log(3, "MESSAGE from " + `strfrom` + " : " + `text`)


# Callback on the delivery status of outgoing pager (MESSAGE)
#   
def on_pager_status(call_id, strto, body, user_data, status, reason):
    write_log(3, "MESSAGE to " + `strto` + " status " + `status` + " reason " + `reason`)


# Received typing indication
#
def on_typing(call_id, strfrom, to, contact, is_typing):
    str_t = ""
    if is_typing:
        str_t = "is typing.."
    else:
        str_t = "has stopped typing"
    write_log(3, "IM indication: " + strfrom + " " + str_t)

# Received the status of previous call transfer request
#
def on_call_transfer_status(call_id,status_code,status_text,final,p_cont):
    strfinal = ""
    if final == 1:
        strfinal = "[final]"
    
    write_log(3, "Call " + `call_id` + ": transfer status= " + `status_code` + " " + status_text+ " " + strfinal)
          
    if status_code/100 == 2:
        write_log(3, "Call " + `call_id` + " : call transfered successfully, disconnecting call")
        status = py_pjsua.call_hangup(call_id, 410, None, None)
        p_cont = 0

# Callback on incoming call transfer request
#       
def on_call_transfer_request(call_id, dst, code):
    write_log(3, "Call transfer request from " + `call_id` + " to " + dst + " with code " + `code`)

#
# Initialize pjsua.
#
def app_init():
    global g_acc_id, g_ua_cfg

    # Create pjsua before anything else
    status = py_pjsua.create()
    if status != 0:
        err_exit("pjsua create() error", status)

    # Create and initialize logging config
    log_cfg = py_pjsua.logging_config_default()
    log_cfg.level = C_LOG_LEVEL
    log_cfg.cb = log_cb

    # Create and initialize pjsua config
    # Note: for this Python module, thread_cnt must be 0 since Python
    #       doesn't like to be called from alien thread (pjsua's thread
    #       in this case)       
    ua_cfg = py_pjsua.config_default()
    ua_cfg.thread_cnt = 0
    ua_cfg.user_agent = "PJSUA/Python 0.1"
    ua_cfg.cb.on_incoming_call = on_incoming_call
    ua_cfg.cb.on_call_media_state = on_call_media_state
    ua_cfg.cb.on_reg_state = on_reg_state
    ua_cfg.cb.on_call_state = on_call_state
    ua_cfg.cb.on_buddy_state = on_buddy_state
    ua_cfg.cb.on_pager = on_pager
    ua_cfg.cb.on_pager_status = on_pager_status
    ua_cfg.cb.on_typing = on_typing
    ua_cfg.cb.on_call_transfer_status = on_call_transfer_status
    ua_cfg.cb.on_call_transfer_request = on_call_transfer_request

    # Create and initialize media config
    med_cfg = py_pjsua.media_config_default()
    med_cfg.ec_tail_len = 0

    #
    # Initialize pjsua!!
    #
    status = py_pjsua.init(ua_cfg, log_cfg, med_cfg)
    if status != 0:
        err_exit("pjsua init() error", status)

    # Configure STUN config
    stun_cfg = py_pjsua.stun_config_default()
    stun_cfg.stun_srv1 = C_STUN_SRV
    stun_cfg.stun_srv2 = C_STUN_SRV
    stun_cfg.stun_port1 = C_STUN_PORT
    stun_cfg.stun_port2 = C_STUN_PORT

    # Configure UDP transport config
    transport_cfg = py_pjsua.transport_config_default()
    transport_cfg.port = C_SIP_PORT
    transport_cfg.stun_config = stun_cfg
    if C_STUN_SRV != "":
        transport_cfg.use_stun = 1

    # Create UDP transport
    status, transport_id = \
        py_pjsua.transport_create(py_pjsua.PJSIP_TRANSPORT_UDP, transport_cfg)
    if status != 0:
        py_pjsua.destroy()
        err_exit("Error creating UDP transport", status)

    # Create initial default account
    status, acc_id = py_pjsua.acc_add_local(transport_id, 1)
    if status != 0:
        py_pjsua.destroy()
        err_exit("Error creating account", status)

    g_acc_id = acc_id
    g_ua_cfg = ua_cfg

# Add SIP account interractively
#
def add_account():
    global g_acc_id

    acc_domain = ""
    acc_username = ""
    acc_passwd =""
    confirm = ""
    
    # Input account configs
    print "Your SIP domain (e.g. myprovider.com): ",
    acc_domain = sys.stdin.readline()
    if acc_domain == "\n": 
        return
    acc_domain = acc_domain.replace("\n", "")

    print "Your username (e.g. alice): ",
    acc_username = sys.stdin.readline()
    if acc_username == "\n":
        return
    acc_username = acc_username.replace("\n", "")

    print "Your password (e.g. secret): ",
    acc_passwd = sys.stdin.readline()
    if acc_passwd == "\n":
        return
    acc_passwd = acc_passwd.replace("\n", "")

    # Configure account configuration
    acc_cfg = py_pjsua.acc_config_default()
    acc_cfg.id = "sip:" + acc_username + "@" + acc_domain
    acc_cfg.reg_uri = "sip:" + acc_domain
    acc_cfg.cred_count = 1
    acc_cfg.cred_info[0].realm = acc_domain
    acc_cfg.cred_info[0].scheme = "digest"
    acc_cfg.cred_info[0].username = acc_username
    acc_cfg.cred_info[0].data_type = 0
    acc_cfg.cred_info[0].data = acc_passwd

    # Add new SIP account
    status, acc_id = py_pjsua.acc_add(acc_cfg, 1)
    if status != 0:
        py_pjsua.perror(THIS_FILE, "Error adding SIP account", status)
    else:
        g_acc_id = acc_id
        write_log(3, "Account " + acc_cfg.id + " added")

def add_player():
    global g_wav_files
    global g_wav_id
    global g_wav_port
    
    file_name = ""
    status = -1
    wav_id = 0
    
    print "Enter the path of the file player(e.g. /tmp/audio.wav): ",
    file_name = sys.stdin.readline()
    if file_name == "\n": 
        return
    file_name = file_name.replace("\n", "")
    status, wav_id = py_pjsua.player_create(file_name, 0)
    if status != 0:
        py_pjsua.perror(THIS_FILE, "Error adding file player ", status)
    else:
        g_wav_files.append(file_name)
        if g_wav_id == 0:
            g_wav_id = wav_id
            g_wav_port = py_pjsua.player_get_conf_port(wav_id)
        write_log(3, "File player " + file_name + " added")
        
def add_recorder():
    global g_rec_file
    global g_rec_id
    global g_rec_port
    
    file_name = ""
    status = -1
    rec_id = 0
    
    print "Enter the path of the file recorder(e.g. /tmp/audio.wav): ",
    file_name = sys.stdin.readline()
    if file_name == "\n": 
        return
    file_name = file_name.replace("\n", "")
    status, rec_id = py_pjsua.recorder_create(file_name, 0, None, 0, 0)
    if status != 0:
        py_pjsua.perror(THIS_FILE, "Error adding file recorder ", status)
    else:
        g_rec_file = file_name
        g_rec_id = rec_id
        g_rec_port = py_pjsua.recorder_get_conf_port(rec_id)
        write_log(3, "File recorder " + file_name + " added")

def conf_list():
    ports = None
    print "Conference ports : "
    ports = py_pjsua.enum_conf_ports()

    for port in ports:
        info = None
        info = py_pjsua.conf_get_port_info(port)
        txlist = ""
        for i in range(info.listener_cnt):
            txlist = txlist + "#" + `info.listeners[i]` + " "
        
        print "Port #" + `info.slot_id` + "[" + `(info.clock_rate/1000)` + "KHz/" + `(info.samples_per_frame * 1000 / info.clock_rate)` + "ms] " + info.name + " transmitting to: " + txlist
        
def connect_port():
    src_port = 0
    dst_port = 0
    
    print "Connect src port # (empty to cancel): "
    src_port = sys.stdin.readline()
    if src_port == "\n": 
        return
    src_port = src_port.replace("\n", "")
    src_port = int(src_port)
    print "To dst port # (empty to cancel): "
    dst_port = sys.stdin.readline()
    if dst_port == "\n": 
        return
    dst_port = dst_port.replace("\n", "")
    dst_port = int(dst_port)
    status = py_pjsua.conf_connect(src_port, dst_port)
    if status != 0:
        py_pjsua.perror(THIS_FILE, "Error connecting port ", status)
    else:       
        write_log(3, "Port connected from " + `src_port` + " to " + `dst_port`)
        
def disconnect_port():
    src_port = 0
    dst_port = 0
    
    print "Disconnect src port # (empty to cancel): "
    src_port = sys.stdin.readline()
    if src_port == "\n": 
        return
    src_port = src_port.replace("\n", "")
    src_port = int(src_port)
    print "From dst port # (empty to cancel): "
    dst_port = sys.stdin.readline()
    if dst_port == "\n": 
        return
    dst_port = dst_port.replace("\n", "")
    dst_port = int(dst_port)
    status = py_pjsua.conf_disconnect(src_port, dst_port)
    if status != 0:
        py_pjsua.perror(THIS_FILE, "Error disconnecting port ", status)
    else:       
        write_log(3, "Port disconnected " + `src_port` + " from " + `dst_port`)

def dump_call_quality():
    global g_current_call
    
    buf = ""
    if g_current_call != -1:
        buf = py_pjsua.call_dump(g_current_call, 1, 1024, "  ")
        write_log(3, "\n" + buf)
    else:
        write_log(3, "No current call")

def xfer_call():
    global g_current_call
    
    if g_current_call == -1:
        
        write_log(3, "No current call")

    else:
        call = g_current_call       
        ci = py_pjsua.call_get_info(g_current_call)
        print "Transfering current call ["+ `g_current_call` + "] " + ci.remote_info
        print "Enter sip url : "
        url = sys.stdin.readline()
        if url == "\n": 
            return
        url = url.replace("\n", "")
        if call != g_current_call:
            print "Call has been disconnected"
            return
        msg_data = py_pjsua.msg_data_init()
        status = py_pjsua.call_xfer(g_current_call, url, msg_data);
        if status != 0:
            py_pjsua.perror(THIS_FILE, "Error transfering call ", status)
        else:       
            write_log(3, "Call transfered to " + url)
        
def xfer_call_replaces():
    if g_current_call == -1:
        write_log(3, "No current call")
    else:
        call = g_current_call
        
        ids = py_pjsua.enum_calls()
        if len(ids) <= 1:
            print "There are no other calls"
            return      

        ci = py_pjsua.call_get_info(g_current_call)
        print "Transfer call [" + `g_current_call` + "] " + ci.remote_info + " to one of the following:"
        for i in range(0, len(ids)):            
            if ids[i] == call:
                continue
            call_info = py_pjsua.call_get_info(ids[i])
            print `ids[i]` + "  " +  call_info.remote_info + "  [" + call_info.state_text + "]"     

        print "Enter call number to be replaced : "
        buf = sys.stdin.readline()
        buf = buf.replace("\n","")
        if buf == "":
            return
        dst_call = int(buf)
        
        if call != g_current_call:
            print "Call has been disconnected"
            return      
        
        if dst_call == call:
            print "Destination call number must not be the same as the call being transfered"
            return
        
        if dst_call >= py_pjsua.PJSUA_MAX_CALLS:
            print "Invalid destination call number"
            return
    
        if py_pjsua.call_is_active(dst_call) == 0:
            print "Invalid destination call number"
            return      

        py_pjsua.call_xfer_replaces(call, dst_call, 0, None)
        
#
# Worker thread function.
# Python doesn't like it when it's called from an alien thread
# (pjsua's worker thread, in this case), so for Python we must
# disable worker thread in pjsua and poll pjsua from Python instead.
#
def worker_thread_main(arg):
    global C_QUIT
    thread_desc = 0;
    status = py_pjsua.thread_register("python worker", thread_desc)
    if status != 0:
        py_pjsua.perror(THIS_FILE, "Error registering thread", status)
    else:
        while C_QUIT == 0:
            py_pjsua.handle_events(50)
        print "Worker thread quitting.."
        C_QUIT = 2


# Start pjsua
#
def app_start():
    # Done with initialization, start pjsua!!
    #
    status = py_pjsua.start()
    if status != 0:
        py_pjsua.destroy()
        err_exit("Error starting pjsua!", status)

    # Start worker thread
    thr = thread.start_new(worker_thread_main, (0,))
    
    print "PJSUA Started!!"


# Print account and buddy list
def print_acc_buddy_list():
    global g_acc_id
    
    acc_ids = py_pjsua.enum_accs()
    print "Account list:"
    for acc_id in acc_ids:
        acc_info = py_pjsua.acc_get_info(acc_id)
        if acc_info.has_registration == 0:
            acc_status = acc_info.status_text
        else:
            acc_status = `acc_info.status` + "/" + acc_info.status_text + " (expires=" + `acc_info.expires` + ")"

        if acc_id == g_acc_id:
            print " *",
        else:
            print "  ",

        print "[" + `acc_id` + "] " + acc_info.acc_uri + ": " + acc_status
        print "       Presence status: ",
        if acc_info.online_status != 0:
            print "Online"
        else:
            print "Invisible"

    if py_pjsua.get_buddy_count() > 0:
        print ""
        print "Buddy list:"
        buddy_ids = py_pjsua.enum_buddies()
        for buddy_id in buddy_ids:
            bi = py_pjsua.buddy_get_info(buddy_id)
            print "   [" + `buddy_id` + "] " + bi.status_text + " " + bi.uri
    
        

       
#get it going ...
app = wxPyApp(filename="output.txt")
app.MainLoop()



#
# Done, quitting..
#
print "PJSUA shutting down.."
C_QUIT = 1
# Give the worker thread chance to quit itself
while C_QUIT != 2:
    py_pjsua.handle_events(50)

print "PJSUA destroying.."
py_pjsua.destroy()



       
---------------------------------

S? un Mejor Amante del Cine
?Quieres saber c?mo? ?Deja que otras personas te ayuden!.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/attachments/20071011/c1d3bff1/attachment-0001.html 


[Index of Archives]     [Asterisk Users]     [Asterisk App Development]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [Linux API]
  Powered by Linux