Again with wx.Timer and Win32

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

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:

[snip monster code]

Suggestions ?

Yeah, please try to reduce the size of your program to the
smallest bit of code that still causes the problem to appear.
Then, if you still haven't figured it out (though usually
by that time you will have), post the smaller program here
and ask for help again.

Posting mega-code and expecting others to try to read through
the whole thing and debug it for you is usually asking a
little much.

(You asked for a suggestion... that's mine. Others might have
more helpful ones, if they have time to try out your code.)

-Peter

···

O-Zone [mailto:liste@zerozone.it] wrote: