Again with the same problem. I wanna understand why ! If i try run Timers.py
from WxPython's Demo, Timers work well. So there's another problem. I Try
launching this code without twisted but i have the same result: no OnTimer
call.
Here's the incriminated code:
#!/usr/bin/env python
# Universal SIP Client
# Copyright (C) 2005 Michele <o-zone@zerozone.it> Pinassi
# DigitelItalia S.p.a. - www.digitelitalia.com
···
#
# Based on Shtoom (http://www.divmod.org/Home/Projects/Shtoom/)
#
# This software is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import wx
from twisted.internet import reactor
from twisted.internet import defer
from twisted.python import log
import MyGlobal
from config import *
from audio import getAudioDevice
from threading import Thread
USE_GENERIC = wx.Platform == '__WXGTK__'
if USE_GENERIC:
from wx.lib.statbmp import GenStaticBitmap as StaticBitmap
else:
StaticBitmap = wx.StaticBitmap
class FatalError(Exception): pass
class DependencyFailure(FatalError): pass
class NoAudioDevice(DependencyFailure): pass
class NoUserInterface(DependencyFailure): pass
class CallFailed(Exception):
sipCode = 500
def __init__(self, args, cookie=None):
self.args = args
self.cookie = cookie
class CallRejected(CallFailed):
sipCode = 603
class CallNotAnswered(CallFailed):
sipCode = 600
class UserBusy(CallFailed):
sipCode = 600
class STUNFailed(CallFailed): pass
class UserBogosity(CallFailed): pass
class HostNotKnown(UserBogosity): pass
class InvalidSIPURL(UserBogosity): pass
# ==========================================================
# GUI
# ==========================================================
class MyDC(wx.Window):
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_BORDER, name=""):
wx.Window.__init__(self, parent, id, pos, size, style, name)
self.parent = parent
self.bmp = wx.Bitmap("img/display.png",wx.BITMAP_TYPE_ANY)
w, h = self.bmp.GetWidth(), self.bmp.GetHeight()
self.SetClientSize( (w, h) )
self.Bind(wx.EVT_PAINT, self.OnPaint)
self._numberTextData = ""
self._statusTextData = ""
self._callTextData = ""
self._drawBuffer = wx.EmptyBitmap(w,h)
dc = wx.BufferedDC(wx.ClientDC(self), self._drawBuffer)
dc.DrawBitmap(self.bmp, 0,0, True)
def OnPaint(self, evt):
dc = wx.BufferedDC(wx.ClientDC(self),self._drawBuffer)
def _doRefresh(self):
self.Refresh()
def ActivateDisplay(self):
self.bmp = wx.Bitmap("img/display.png",wx.BITMAP_TYPE_ANY)
self.ClearDisplay()
def ClearDisplay(self):
dc = wx.BufferedDC(wx.ClientDC(self), self._drawBuffer)
dc.Clear()
dc.DrawBitmap(self.bmp, 0,0, True)
self._doRefresh()
def _writeText(self,text,x,y,size=10):
font = wx.Font(size, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False,
"MacType")
dc = wx.BufferedDC(wx.ClientDC(self), self._drawBuffer)
dc.SetFont(font)
dc.DrawText(text,x,y)
self._doRefresh()
def _refreshText(self):
self.ClearDisplay()
self._writeText(self._statusTextData,4,5,10)
self._writeText(self._numberTextData,4,17,20)
self._writeText(self._callTextData,4,40,20)
def StatusText(self,text):
self._statusTextData = text
self._refreshText()
def NumberText(self,text):
self._numberTextData = text
self._refreshText()
def CallText(self,text):
self._callTextData = text
self._refreshText()
class MyTimer(wx.Timer):
def __init__(self, master):
wx.Timer.__init__(self)
self.master = master
def Start(self, dt):
if self.IsRunning():
pass
else:
wx.Timer.Start(self, dt)
def Notify(self):
self.master.OnTimer()
class MainWindow(wx.Frame):
_audioth = None
_registered = False
_pending = False
_cookie = None
def __init__(self, *args, **kwds):
# GUI
#kwds["style"] = wx.DEFAULT_FRAME_STYLE
kwds["style"] = wx.FRAME_SHAPED | wx.SIMPLE_BORDER | wx.STAY_ON_TOP # |
wx.FRAME_NO_TASKBAR
wx.Frame.__init__(self, *args, **kwds)
self.SetTitle("UniversalSIPClient")
# Background
self.bmp = wx.Bitmap("img/base.png",wx.BITMAP_TYPE_ANY)
w, h = self.bmp.GetWidth(), self.bmp.GetHeight()
self.SetClientSize( (w, h) )
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.display = None
# Items
bmp = wx.Bitmap("img/bot_exit.png", wx.BITMAP_TYPE_ANY)
self.button_QUIT = StaticBitmap(self, -1, bmp, (190, 12),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_1.png", wx.BITMAP_TYPE_ANY)
self.button_K1 = StaticBitmap(self, -1, bmp, (20, 127),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_2.png", wx.BITMAP_TYPE_ANY)
self.button_K2 = StaticBitmap(self, -1, bmp, (69, 127),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_3.png", wx.BITMAP_TYPE_ANY)
self.button_K3 = StaticBitmap(self, -1, bmp, (117, 127),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_rispondi.png", wx.BITMAP_TYPE_ANY)
self.button_KOK = StaticBitmap(self, -1, bmp, (164, 127),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_4.png", wx.BITMAP_TYPE_ANY)
self.button_K4 = StaticBitmap(self, -1, bmp, (20, 152),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_5.png", wx.BITMAP_TYPE_ANY)
self.button_K5 = StaticBitmap(self, -1, bmp, (69, 152),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_6.png", wx.BITMAP_TYPE_ANY)
self.button_K6 = StaticBitmap(self, -1, bmp, (117, 152),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_riaggancia.png", wx.BITMAP_TYPE_ANY)
self.button_KKO = StaticBitmap(self, -1, bmp, (164, 152),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_7.png", wx.BITMAP_TYPE_ANY)
self.button_K7 = StaticBitmap(self, -1, bmp, (20, 174),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_8.png", wx.BITMAP_TYPE_ANY)
self.button_K8 = StaticBitmap(self, -1, bmp, (69, 174),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_9.png", wx.BITMAP_TYPE_ANY)
self.button_K9 = StaticBitmap(self, -1, bmp, (117, 174),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_menu.png", wx.BITMAP_TYPE_ANY)
self.button_KMENU = StaticBitmap(self, -1, bmp, (164, 174),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_asterisco.png", wx.BITMAP_TYPE_ANY)
self.button_KAST = StaticBitmap(self, -1, bmp, (20, 196),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_0.png", wx.BITMAP_TYPE_ANY)
self.button_K0 = StaticBitmap(self, -1, bmp, (69, 196),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_#.png", wx.BITMAP_TYPE_ANY)
self.button_KCAN = StaticBitmap(self, -1, bmp, (117, 196),
(bmp.GetWidth(), bmp.GetHeight()))
bmp = wx.Bitmap("img/bot_rubrica.png", wx.BITMAP_TYPE_ANY)
self.button_KRUB = StaticBitmap(self, -1, bmp, (164, 196),
(bmp.GetWidth(), bmp.GetHeight()))
self.hasShape = False
self.delta = (0,0)
# BUTTON BIND
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.button_QUIT.Bind(wx.EVT_LEFT_DOWN, self.QUIT_Button)
self.button_K1.Bind(wx.EVT_LEFT_DOWN, self.K1_Button)
self.button_K2.Bind(wx.EVT_LEFT_DOWN, self.K2_Button)
self.button_K3.Bind(wx.EVT_LEFT_DOWN, self.K3_Button)
self.button_K4.Bind(wx.EVT_LEFT_DOWN, self.K4_Button)
self.button_K5.Bind(wx.EVT_LEFT_DOWN, self.K5_Button)
self.button_K6.Bind(wx.EVT_LEFT_DOWN, self.K6_Button)
self.button_K7.Bind(wx.EVT_LEFT_DOWN, self.K7_Button)
self.button_K8.Bind(wx.EVT_LEFT_DOWN, self.K8_Button)
self.button_K9.Bind(wx.EVT_LEFT_DOWN, self.K9_Button)
self.button_K0.Bind(wx.EVT_LEFT_DOWN, self.K0_Button)
self.button_KOK.Bind(wx.EVT_LEFT_DOWN, self.OK_Button)
self.button_KKO.Bind(wx.EVT_LEFT_DOWN, self.CANCEL_Button)
self.button_KAST.Bind(wx.EVT_LEFT_DOWN, self.KAST_Button)
self.button_KCAN.Bind(wx.EVT_LEFT_DOWN, self.KCAN_Button)
self.button_KRUB.Bind(wx.EVT_LEFT_DOWN, self.KRUB_Button)
self.button_KMENU.Bind(wx.EVT_LEFT_DOWN, self.KMENU_Button)
# Other STUFF
self.dialNumber = ""
self.displayNumber = ""
self.sipURL = ""
MyGlobal.myQueueMAIN.put(("REGISTER",0))
if wx.Platform == "__WXGTK__":
self.Bind(wx.EVT_WINDOW_CREATE, self.SetWindowShape)
else:
self.SetWindowShape()
# Attiva il timer della Queue
self.timer = MyTimer(self)
self.timer.Start(250)
# =============================== EVENTS CALLBACKS ===========================
def SetWindowShape(self, *evt):
r = wx.RegionFromBitmap(self.bmp)
self.hasShape = self.SetShape(r)
def OnLeftDown(self, evt):
self.CaptureMouse()
x, y = self.ClientToScreen(evt.GetPosition())
originx, originy = self.GetPosition()
dx = x - originx
dy = y - originy
self.delta = ((dx, dy))
def OnLeftUp(self, evt):
if self.HasCapture():
self.ReleaseMouse()
def OnMouseMove(self, evt):
if evt.Dragging() and evt.LeftIsDown():
x, y = self.ClientToScreen(evt.GetPosition())
fp = (x - self.delta[0], y - self.delta[1])
self.Move(fp)
def OnPaint(self,evt):
# First Time ?
if self.display is None:
self.display = MyDC(self, -1, (20,50))
dc = wx.PaintDC(self)
dc.DrawBitmap(self.bmp, 0,0, True)
self.display.StatusText("IN ATTESA DI REGISTRAZIONE")
else:
dc = wx.PaintDC(self)
dc.DrawBitmap(self.bmp, 0,0, True)
self.display.Refresh()
def OnMouseLeftDown(self,evt):
(x,y) = evt.GetPositionTuple()
def OnKeyPressed(self,evt):
keycode = evt.GetKeyCode()
print "Key Pressed: %d"%keycode
# =============================== BUTTON CALLBACKS ===========================
def OK_Button(self,evt):
MyGlobal.myQueueMAIN.put(("OKBUTTON",(self.dialNumber,0)))
self.dialNumber = ""
def CANCEL_Button(self,evt):
MyGlobal.myQueueMAIN.put(("CANCBUTTON",(self.dialNumber,0)))
self.dialNumber = ""
def K1_Button(self,evt):
if self._cookie is None:
self.dialNumber = self.dialNumber+"1"
else:
self.playDTMF("1")
def K2_Button(self,evt):
if self._cookie is None:
self.dialNumber = self.dialNumber+"2"
else:
self.playDTMF("2")
def K3_Button(self,evt):
if self._cookie is None:
self.dialNumber = self.dialNumber+"3"
else:
self.playDTMF("3")
def K4_Button(self,evt):
self.dialNumber = self.dialNumber+"4"
def K5_Button(self,evt):
self.dialNumber = self.dialNumber+"5"
def K6_Button(self,evt):
self.dialNumber = self.dialNumber+"6"
def K7_Button(self,evt):
self.dialNumber = self.dialNumber+"7"
def K8_Button(self,evt):
self.dialNumber = self.dialNumber+"8"
def K9_Button(self,evt):
self.dialNumber = self.dialNumber+"9"
def K0_Button(self,evt):
self.dialNumber = self.dialNumber+"0"
def KAST_Button(self,evt):
self.dialNumber = self.dialNumber+"*"
def KCAN_Button(self,evt):
self.dialNumber = self.dialNumber+"#"
def KRUB_Button(self,evt):
pass
def KMENU_Button(self,evt):
dlgconfig = CfgDialog(None, -1, "")
dlgconfig.Show()
def QUIT_Button(self,evt):
MyGlobal.myQueueMAIN.put(("QUIT",0))
self.Close()
def playDTMF(self, key):
MyGlobal.myQueueMAIN.put(("DTMF",(key,0)))
# =============================== EVENTS ===========================
def OnTimer(self):
if self._audioth is not None:
if self._audioth.isAlive() is not True:
self._audioth = None
# Other Stuff
if self._pending: # Chiamate in attesa ? Squilla !!!
self.playSOUND("fx/ring.mp3")
# Se stiamo componedo visualizza il numero
if self.dialNumber is not self.displayNumber:
self.display.NumberText(self.dialNumber)
self.displayNumber = self.dialNumber
# Fine
# ANALIZZA LA QUEUE PER EVENTUALI AZIONI
if MyGlobal.myQueueGUI.empty() is False:
try:
(cmd,args) = MyGlobal.myQueueGUI.get(0,1)
except Exception,e:
log.err('myQueueGUI.get error: %s'%e)
log.msg('myQueueGUI.get = (%s-%s)'%(cmd,args))
if cmd == "STATUSTEXT":
if self.display is not None:
self.display.StatusText(args[0])
if cmd == "CALLTEXT":
if self.display is not None:
self.display.CallText(args[0])
if cmd == "REGISTER":
if args[0] == "OK":
if self.display is not None:
self.display.ActivateDisplay()
self.display.NumberText("")
self.display.StatusText("Welcome %s, you're on-line
now."%MyGlobal.DisplayUser)
self._registered = True
if cmd == "BUTTON":
if args[0] == "HANGUP":
if args[1] == "ON":
self.button_KKO.SetBitmap(wx.Bitmap("img/bot_riaggancia_on.png",
wx.BITMAP_TYPE_ANY))
if args[1] == "OFF":
self.button_KKO.SetBitmap(wx.Bitmap("img/bot_riaggancia.png",
wx.BITMAP_TYPE_ANY))
if args[0] == "ANSWER":
if args[1] == "ON":
self.button_KOK.SetBitmap(wx.Bitmap("img/bot_rispondi_on.png",
wx.BITMAP_TYPE_ANY))
if args[1] == "OFF":
self.button_KOK.SetBitmap(wx.Bitmap("img/bot_rispondi.png",
wx.BITMAP_TYPE_ANY))
def OnCloseWindow(self, event):
MyGlobal.myQueueMAIN.put(("QUIT",0))
self.Close()
# =============================== AUDIO STUFF ===========================
def playSOUND(self,fname):
if self._audioth is None:
audioth = AudioThread(fname)
audioth.start()
self._audioth = audioth
# end of class MainWindow
class AudioThread(Thread):
def __init__(self,fname): # Create AUDIO Thread
self.fname = fname
Thread.__init__(self)
def run(self): # Thread loop
import pymedia.audio.sound as sound
import pymedia.audio.acodec as acodec
import time
dec = acodec.Decoder('mp3')
snd = None
f = open(self.fname, 'rb')
s = f.read(100000)
r = dec.decode(s)
if snd == None:
snd = sound.Output(r.sample_rate, r.channels, sound.AFMT_S16_LE)
if r:
data = r.data
snd.play(data)
while snd.isPlaying():
time.sleep(0.05)
# ==========================================================
# NETWORK
# ==========================================================
class TwistedHandler:
def fetch(self):
reactor.startRunning()
def poll(self):
if reactor.running:
reactor.runUntilCurrent()
reactor.doIteration(0)
return reactor.running
def pending(self):
return reactor.running
def stop(self):
reactor.stop()
class MainThread(Thread): # Thread principale
__cookieCount = 0
_pending = False
_cookie = None
_registered = False
_muted = False
def __init__(self):
# Twisted
self.twisted = TwistedHandler()
self.twisted.fetch()
Thread.__init__(self)
def run(self):
# AUDIO Stuff
self._audio = None
#self.openAudioDevice()
self.dialNumber = ""
# Configurazione
MyGlobal.Version = "1.0.0"
self.config = Configuration()
self.config.LOADConfig()
MyGlobal.audioSystem = ""
MyGlobal.audioIn = ""
MyGlobal.audioOut = ""
(dummy,MyGlobal.Registrar) = MyGlobal.RegisterURI.split("@",1)
# SIP Stuff
self._calls = {}
self._rtp = {}
self._currentCall = None
self._rtpProtocolClass = None
# Install SIP Phone Object
import sip
p = sip.SipProtocol(self)
self.sip = p
if MyGlobal.LocalSIPPort is None:
listenport = 5060
else:
listenport = MyGlobal.LocalSIPPort
self.sipListener = reactor.listenUDP(listenport, p)
log.msg("# SIP listener installed on port %d"%(listenport))
RUN=True
# Twisted Stuff
while(RUN):
if MyGlobal.myQueueMAIN.empty() is False:
try:
(cmd,args) = MyGlobal.myQueueMAIN.get(0,1)
except Exception,e:
log.err('myQueueMAIN.get error: %s'%e)
log.msg('myQueueMAIN.get = (%s-%s)'%(cmd,args))
# Esci dal programma
if cmd == "QUIT":
RUN=False
self.stop()
# Avvia Registrazione sul server
if cmd == "REGISTER":
self.sip.register()
# Riproduci DTMF
if cmd == "DTMF":
self.playDTMF(args[0])
# L'utente ha premuto il tasto OK
if cmd == "OKBUTTON":
# Se ci sono chiamate in attesa di risposta...
if self._pending:
self._incoming_timeout.cancel()
self._incoming_timeout = None
self.cookie, resp = self._pending
self._pending = None
resp.callback(self._cookie)
# ...altrimenti effettua la chiamata !
else:
self.dialNumber = args[0]
if self._registered:
self.sipURL = 'sip:'+self.dialNumber+'@'+MyGlobal.Registrar
if self._cookie is None:
self.sipURL = 'sip:enrico@192.168.1.203'
self.sip.placeCall(self.sipURL)
else:
self.callMessage("IN CORSO")
else:
self.sip.register()
self.statusMessage("IN ATTESA DI REGISTRAZIONE")
# L'utente ha premuto il tasto CANC
if cmd == "CANCBUTTON":
self.dialNumber = args[0]
if self._pending:
self._incoming_timeout.cancel()
self._incoming_timeout = None
self.cookie, resp = self._pending
self._pending = None
resp.callback(CallRejected('no thanks', cookie))
# ...altrimenti controlla e riattacca eventuali chiamate !
else:
self.dropCall(self._cookie)
self.callMessage("")
self.twisted.poll()
log.msg("-[LOG END]---------------------------------------------------");
def stop(self):
self.config.SAVEConfig()
reactor.stop()
self.twisted.stop()
# ======================== INTERFACCE CON LA GUI =======================
def statusMessage(self, message):
MyGlobal.myQueueGUI.put(("STATUSTEXT",(message,0)))
def callMessage(self, message):
MyGlobal.myQueueGUI.put(("CALLTEXT",(message,0)))
def debugMessage(self, message): # Messaggi di errore/debug
log.msg("DEBUG: %s\n" % message)
def registrationOK(self,sip):
self._registered = True
MyGlobal.myQueueGUI.put(("REGISTER",("OK",0)))
# =============================== VOIP STUFF ===========================
def playDTMF(self, key):
import time
duration = 0.1
if key not in '01234567890#*, ':
return
self.appStartDTMF(self._cookie, key)
time.sleep(duration)
self.appStopDTMF(self._cookie, key)
def getCookie(self):
self.__cookieCount += 1
return "CallCookie%d"%(self.__cookieCount)
def authCred(self, method, uri, realm='unknown', retry=False):
user = MyGlobal.AuthUsername
passwd = MyGlobal.AuthPassword
if user is not None and passwd is not None and retry is False:
return
defer.succeed((MyGlobal.AuthUsername,MyGlobal.AuthPassword))
else:
return defer.fail(CallFailed("No auth available"))
def acceptCall(self, call):
log.msg("dialog is %r"%(call.dialog))
cookie = self.getCookie()
self._calls[cookie] = call
calltype = call.dialog.getDirection()
if calltype == 'inbound':
# Commented out until I test it
uidef = self.incomingCall(call.dialog.getCaller(), cookie)
uidef.addCallback(lambda x: self._createRTP(x,
call.getLocalSIPAddress()[0],
call.getSTUNState()))
return uidef
elif calltype == 'outbound':
self.openAudioDevice()
return self._createRTP(cookie, call.getLocalSIPAddress()[0],
call.getSTUNState())
else:
raise ValueError, "unknown call type %s"%(calltype)
return d
def startCall(self, callcookie, remoteSDP, cb):
log.msg("startCall reopening %r %r"%(self._currentCall, self._audio))
md = remoteSDP.getMediaDescription('audio')
ipaddr = md.ipaddr or remoteSDP.ipaddr
remoteAddr = (ipaddr, md.port)
if not self._currentCall:
self._audio.reopen()
log.msg("call Start %r %r"%(callcookie, remoteAddr))
self._rtp[callcookie].startSendingAndReceiving(remoteAddr)
self._currentCall = callcookie
self.callConnected(callcookie)
cb(callcookie)
def endCall(self, callcookie, reason=''):
rtp = self._rtp.get(callcookie)
log.msg("endCall clearing %r"%(callcookie))
self._currentCall = None
if rtp:
rtp = self._rtp[callcookie]
rtp.stopSendingAndReceiving()
del self._rtp[callcookie]
if self._calls.get(callcookie):
del self._calls[callcookie]
self.closeAudioDevice()
self.callDisconnected(callcookie, reason)
def dropCall(self, cookie):
call = self._calls.get(cookie)
if call:
d = call.dropCall()
def callStarted(self, cookie):
self._cookie = cookie
log.msg("Call %s STARTED"%(self._cookie), system='ui')
self.callMessage("SQUILLANDO")
MyGlobal.myQueueGUI.put(("BUTTON",("HANGUP","ON")))
def callConnected(self, cookie):
log.msg("Call to %s CONNECTED"%(self.sipURL), system='ui')
MyGlobal.myQueueGUI.put(("BUTTON",("HANGUP","ON")))
self.callMessage("CONNESSO")
def callFailed(self, e, message=None):
log.msg("Call to %s FAILED: %r"%(self.sipURL, e), system='ui')
self._pending = None
self.callMessage("FALLITO")
MyGlobal.myQueueGUI.put(("BUTTON",("HANGUP","OFF")))
MyGlobal.myQueueGUI.put(("BUTTON",("ANSWER","OFF")))
def callDisconnected(self, cookie, message):
log.msg("Call to %s DISCONNECTED"%(self.sipURL), system='ui')
self._cookie = None
self._pending = None
self.callMessage("DISCONNESSO")
MyGlobal.myQueueGUI.put(("BUTTON",("HANGUP","OFF")))
MyGlobal.myQueueGUI.put(("BUTTON",("ANSWER","OFF")))
def incomingCall(self, description, cookie):
import re
#if self._pending is not None:
# return defer.fail(UserBusy(600))
defresp = defer.Deferred()
self._pending = ( cookie, defresp )
self._incoming_timeout = reactor.callLater(20,
lambda :self._timeout_incoming(self._pending))
log.msg("INCOMING CALL: %s\n"%description)
# Fai un parse e prendi solo quello che c' tra le ""
numero = re.compile(r'"(.*?)"').findall("%s"%description)
self.callMessage("* %s *"%numero[0])
MyGlobal.myQueueGUI.put(("BUTTON",("HANGUP","ON")))
MyGlobal.myQueueGUI.put(("BUTTON",("ANSWER","ON")))
return defresp
def selectDefaultFormat(self, callcookie, sdp):
md = sdp.getMediaDescription('audio')
rtpmap = md.rtpmap
ptlist = [ x[1] for x in rtpmap.values() ]
log.msg("PTLIST:%s"%(ptlist))
def getSDP(self, callcookie, othersdp=None):
rtp = self._rtp[callcookie]
sdp = rtp.getSDP(othersdp)
return sdp
def _timeout_incoming(self, which):
log.msg("CALL NOT ANSWERED\n")
self._incoming_timeout = None
cookie, resp = self._pending
self._pending = None
self.callMessage("")
resp.callback(CallNotAnswered('not answering', cookie))
# =============================== RTP STUFF ===========================
def _createRTP(self, cookie, localIP, withSTUN):
from rtp.protocol import RTPProtocol
if isinstance(cookie, CallFailed):
del self._calls[cookie.cookie]
return defer.succeed(cookie)
self.openAudioDevice()
self.callStarted(cookie)
if self._rtpProtocolClass is None:
rtp = RTPProtocol(self, cookie)
else:
rtp = self._rtpProtocolClass(self, cookie)
self._rtp[cookie] = rtp
d = rtp.createRTPSocket(localIP,withSTUN)
return d
def receiveRTP(self, callcookie, packet):
if self._currentCall != callcookie:
return None
try:
self._audio.write(packet)
except IOError:
pass
def giveRTP(self, callcookie):
# Check that callcookie is the active call
if self._currentCall != callcookie or self._muted:
return None # comfort noise
packet = self._audio.read()
if packet is None:
return None
else:
return packet
def getSDP(self, callcookie, othersdp=None):
rtp = self._rtp[callcookie]
sdp = rtp.getSDP(othersdp)
return sdp
def appStartDTMF(self, cookie, digit):
rtp = self._rtp[cookie]
rtp.startDTMF(digit)
def appStopDTMF(self, cookie, digit):
rtp = self._rtp[cookie]
rtp.stopDTMF(digit)
# =============================== AUDIO STUFF ===========================
def openAudioDevice(self):
if self._audio is None:
audioPref = MyGlobal.audioSystem
audio_in = MyGlobal.audioIn
audio_out = MyGlobal.audioOut
if audio_in and audio_out:
aF = ( audio_in, audio_out )
else:
aF = None
log.msg("Getting new audio device", system='phone')
self._audio = getAudioDevice()
if self._audio is None:
log.err("NO AUDIO DEVICE AVAILABLE")
else:
self._audio.close()
log.msg("Got new audio device")
def closeAudioDevice(self):
if self._audio is not None:
self._audio.close()
self._audioFormat = None
self._audio = None
#--------------------------------------------------------------------------------#
import Queue
MyGlobal.myQueueMAIN = Queue.Queue()
MyGlobal.myQueueGUI = Queue.Queue()
if __name__ == '__main__':
import sys
#if wx.Platform == "__WXGTK__":
log.startLogging(sys.stderr, 0)
#else:
# log.startLogging(open('usipc.log', 'a'), 0)
log.msg("-[LOG
START]---------------------------------------------------");
# Twisted thread (a REAL Thread)
from twisted.python import threadable
threadable.init()
mainth = MainThread()
mainth.start()
# GUI Thread (the main loop)
app = wx.PySimpleApp(0)
frame_1 = MainWindow(None, -1, "")
wx.InitAllImageHandlers()
frame_1.Show()
app.SetTopWindow(frame_1)
app.MainLoop()
As you can see, i ran WX in the main thread and Twisted in a secondary thread.
Because there's no special need to comunicate between Twisted and WX, i use
Queues (that are thread-safe).
Of course this is not a well-written code; first i need to let it working
under Win32.
Suggestions ?
--
------
O-Zone ! www.zerozone.it