Example #1
0
class DependentMultiService(MultiService):
    """
    I am a MultiService that starts services in insert order,
    and stops them in the reverse order.  The service starts
    and stops are chained, so be very careful about services
    that may fail to start or stop.
    """
    def __init__(self, serviceName, serviceParent=None):
        MultiService.__init__(self, serviceName, serviceParent)
        self.services = OrderedDict(self.services)
    def _finishStartService(self, res):
        return ApplicationService.startService(self) or defer.succeed(None)
    def _rollbackStartedServices(self, failure, service):
        v = self.services.values()
        startedServices = v[:v.index(service)]
        startedServices.reverse()
        for svc in startedServices:
            svc.stopService()
        return failure
    def startService(self):
        """
        Start all of my Services.
        I return a Deferred that will callback (with no useful result)
        when all services are started.  In the event of a failure, all 
        of the successful services will be stopped (without chained behavior)
        and I will errback with the first unsuccessful service's failure.
        """
        def startServiceDeferred(res, service):
            return service.startService() or defer.succeed(None)
        d = defer.succeed(None)
        for svc in self.services.values():
            d.addCallbacks(startServiceDeferred, callbackArgs=(svc,),
                errback=self._rollbackStartedServices, errbackArgs=(svc,))
        return d.addCallback(self._finishStartService)
    def _emergencyStopService(self, failure, service):
        v = self.services.values()
        runningServices = v[v.index(service):]
        runningServices.reverse()
        for svc in runningServices:
            svc.stopService()
        self._finishStopService()
        return failure
    def _finishStopService(self, res):
        return ApplicationService.stopService(self) or defer.succeed(None)
    def stopService(self):
        """
        Stop all of my Services.
        I return a Deferred that will callback (with no useful result)
        when all services are stopped.  In the event of a failure, the 
        running services will be stopped (without chained behavior) and 
        I will errback with the first unsuccessful service's failure.
        """
        def stopServiceDeferred(res, service):
            return service.stopService() or defer.succeed(None)
        v = self.services.values()
        v.reverse()
        d = defer.succeed(None)
        for svc in v:
            d.addCallbacks(stopServiceDeferred, callbackArgs=(svc,),
                errback=self._emergencyStopService, errbackArgs=(svc,))
        return d.addCallback(self._finishStopService)
Example #2
0
class VoiceApp(StateMachine):

    _inbound = None

    def __init__(self, defer, appl, cookie, **kwargs):
        self.__cookie = cookie
        self.__appl = appl
        self.__legs = OrderedDict()
        self.__dict__.update(kwargs)
        self.__currentDTMFKey = None
        self.__collectedDTMFKeys = ''
        self.__dtmfSingleMode = True
        super(VoiceApp, self).__init__(defer, **kwargs)

    def getDefaultLeg(self):
        if self.__legs:
            return self.__legs.values()[0]

    def getLeg(self, cookie):
        return self.__legs.get(cookie)

    def setLeg(self, leg, cookie):
        self.__legs[cookie] = leg
        #self.leg.hijackLeg(self)

    def va_selectDefaultFormat(self, ptlist, callcookie):
        return self.getLeg(callcookie).selectDefaultFormat(ptlist)

    def va_incomingRTP(self, packet, callcookie):
        leg = self.getLeg(callcookie)
        if leg is None:
            log.msg('no leg for cookie %s for incoming RTP'%(callcookie,),
                                                                system='doug')
            return
        else:
            return leg.leg_incomingRTP(packet)

    def va_outgoingRTP(self, sample, cookie=None):
        if cookie is None:
            cookie = self.__cookie
        self.__appl.outgoingRTP(cookie, sample)

    def va_start(self, args):
        self._start(callstart=0, args=args)

    def va_callstart(self, inboundLeg, args=None):
        if args is None:
            args = {}
        if inboundLeg is not None:
            self.__legs[inboundLeg.getCookie()] = inboundLeg
            if self._inbound is None:
                self._inbound = inboundLeg
        ce = CallStartedEvent(inboundLeg)
        ce.args = args
        self._triggerEvent(ce)

    def va_callanswered(self, leg=None):
        if leg is None:
            leg = self._inbound
        self._triggerEvent(CallAnsweredEvent(leg))

    def va_callrejected(self, leg=None):
        if leg is None:
            leg = self._inbound
        try:
            del self.__legs[leg]
        except KeyError:
            log.msg("can't find leg %s, current legs: %r"%(
                                    leg, self.__legs.keys()),
                                    system='doug')
        self._triggerEvent(CallRejectedEvent(leg))

    def _clear_legs(self):
        from shtoom.util import stack
        #print self, "clearing running legs %r"%(self.__legs.items())#,stack(8)
        for name, leg in self.__legs.items():
            leg._stopAudio()
            del self.__legs[name]

    _cleanup = _clear_legs

    def va_abort(self):
        self.mediaStop()
        self._clear_legs()
        self._triggerEvent(CallEndedEvent(None))

    def mediaPlay(self, playlist, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        leg.mediaPlay(playlist)

    def mediaRecord(self, dest, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        leg.mediaRecord(dest)

    def mediaStop(self, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        if leg is not None:
            leg.mediaStop()

    def mediaStopRecording(self, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        if leg is not None:
            leg.mediaStopRecording()

    def setTimer(self, delay):
        return Timer(self, delay)

    def isPlaying(self, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        return leg.isPlaying()

    def isRecording(self, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        return leg.isRecording()

    def dtmfMode(self, single=False, inband=False, timeout=0, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        leg.dtmfMode(single, inband, timeout)

    def placeCall(self, toURI, fromURI=None):
        from shtoom.doug.leg import Leg
        nleg = Leg(cookie=None, dialog=None, voiceapp=self)
        self.__appl.placeCall(self.__cookie, nleg, toURI, fromURI)

    def va_hangupCall(self, cookie):
        self.__appl.dropCall(cookie)

    def connectLegs(self, leg1, leg2=None):
        from shtoom.doug.leg import Bridge

        if leg2 is None:
            leg2 = self.getDefaultLeg()
        if leg1 is leg2:
            raise ValueError, "can't join %r to itself!"%(leg1)
        else:
            b = Bridge(leg1, leg2)
            return b

    def sendDTMF(self, digits, cookie=None, duration=0.1, delay=0.05):
        "Send a string of DTMF keystrokes"
        for n,key in enumerate(digits):
            if key not in ',01234567890#*':
                raise ValueError, key
            if key == ',':
                # pause
                continue
            n = float(n) # just in case
            if cookie is None:
                cookie = self.__cookie
            i = 0.2
            reactor.callLater(i+n*(duration+delay),
                lambda k=key: self.__appl.startDTMF(cookie, k))
            reactor.callLater(i+n*(duration+delay)+duration,
                lambda k=key: self.__appl.stopDTMF(cookie, k))

    def _inboundDTMFKeyPress(self, dtmf):
        if self.__dtmfSingleMode:
            self._triggerEvent(DTMFReceivedEvent(dtmf, self))
        else:
            self.__collectedDTMFKeys += dtmf
            if dtmf in ('#', '*'):
                dtmf, self.__collectedDTMFKeys = self.__collectedDTMFKeys, ''
                self._triggerEvent(DTMFReceivedEvent(dtmf, self))

    def va_startDTMFevent(self, dtmf, cookie=None):
        c = self.__currentDTMFKey
        if dtmf:
            if c is not dtmf:
                self.va_stopDTMFevent(c)
                self.__currentDTMFKey = dtmf
                self._inboundDTMFKeyPress(dtmf)
            else:
                # repeat
                pass

    def va_stopDTMFevent(self, dtmf, cookie=None):
        # For now, I only care about dtmf start events
        if dtmf == self.__currentDTMFKey:
            self.__currentDTMFKey = None
Example #3
0
class DependentMultiService(MultiService):
    """
    I am a MultiService that starts services in insert order,
    and stops them in the reverse order.  The service starts
    and stops are chained, so be very careful about services
    that may fail to start or stop.
    """
    def __init__(self, serviceName, serviceParent=None):
        MultiService.__init__(self, serviceName, serviceParent)
        # Ensure order
        self.services = OrderedDict(self.services)

    def _finishStartService(self, res):
        return ApplicationService.startService(self) or defer.succeed(None)

    def _rollbackStartedServices(self, failure, service):
        v = self.services.values()
        startedServices = v[:v.index(service)]
        startedServices.reverse()
        # Warning:  On failure, service stops are not
        # chained.  However, they will stop in the proper order.
        for svc in startedServices:
            svc.stopService()
        return failure

    def startService(self):
        """
        Start all of my Services.

        I return a Deferred that will callback (with no useful result)
        when all services are started.  In the event of a failure, all 
        of the successful services will be stopped (without chained behavior)
        and I will errback with the first unsuccessful service's failure.
        """
        def startServiceDeferred(res, service):
            return service.startService() or defer.succeed(None)

        d = defer.succeed(None)
        for svc in self.services.values():
            d.addCallbacks(startServiceDeferred,
                           callbackArgs=(svc, ),
                           errback=self._rollbackStartedServices,
                           errbackArgs=(svc, ))
        return d.addCallback(self._finishStartService)

    def _emergencyStopService(self, failure, service):
        v = self.services.values()
        runningServices = v[v.index(service):]
        runningServices.reverse()
        for svc in runningServices:
            svc.stopService()
        # It is probably desirable that the service collection be
        # marked as stopped, even though errors have occurred.
        self._finishStopService()
        return failure

    def _finishStopService(self, res):
        return ApplicationService.stopService(self) or defer.succeed(None)

    def stopService(self):
        """
        Stop all of my Services.

        I return a Deferred that will callback (with no useful result)
        when all services are stopped.  In the event of a failure, the 
        running services will be stopped (without chained behavior) and 
        I will errback with the first unsuccessful service's failure.
        """
        def stopServiceDeferred(res, service):
            return service.stopService() or defer.succeed(None)

        v = self.services.values()
        v.reverse()
        d = defer.succeed(None)
        for svc in v:
            d.addCallbacks(stopServiceDeferred,
                           callbackArgs=(svc, ),
                           errback=self._emergencyStopService,
                           errbackArgs=(svc, ))
        return d.addCallback(self._finishStopService)
Example #4
0
class VoiceApp(StateMachine):

    _inbound = None

    def __init__(self, defer, appl, cookie, **kwargs):
        self.__cookie = cookie
        self.__appl = appl
        self.__legs = OrderedDict()
        self.__dict__.update(kwargs)
        self.__currentDTMFKey = None
        self.__collectedDTMFKeys = ''
        self.__dtmfSingleMode = True
        super(VoiceApp, self).__init__(defer, **kwargs)

    def getDefaultLeg(self):
        if self.__legs:
            return self.__legs.values()[0]

    def getLeg(self, cookie):
        return self.__legs.get(cookie)

    def setLeg(self, leg, cookie):
        self.__legs[cookie] = leg
        #self.leg.hijackLeg(self)

    def va_selectDefaultFormat(self, ptlist, callcookie):
        return self.getLeg(callcookie).selectDefaultFormat(ptlist)

    def va_incomingRTP(self, packet, callcookie):
        leg = self.getLeg(callcookie)
        if leg is None:
            log.msg('no leg for cookie %s for incoming RTP' % (callcookie, ),
                    system='doug')
            return
        else:
            return leg.leg_incomingRTP(packet)

    def va_outgoingRTP(self, sample, cookie=None):
        if cookie is None:
            cookie = self.__cookie
        self.__appl.outgoingRTP(cookie, sample)

    def va_start(self, args):
        self._start(callstart=0, args=args)

    def va_callstart(self, inboundLeg, args=None):
        if args is None:
            args = {}
        if inboundLeg is not None:
            self.__legs[inboundLeg.getCookie()] = inboundLeg
            if self._inbound is None:
                self._inbound = inboundLeg
        ce = CallStartedEvent(inboundLeg)
        ce.args = args
        self._triggerEvent(ce)

    def va_callanswered(self, leg=None):
        if leg is None:
            leg = self._inbound
        self._triggerEvent(CallAnsweredEvent(leg))

    def va_callrejected(self, leg=None):
        if leg is None:
            leg = self._inbound
        try:
            del self.__legs[leg]
        except KeyError:
            log.msg("can't find leg %s, current legs: %r" %
                    (leg, self.__legs.keys()),
                    system='doug')
        self._triggerEvent(CallRejectedEvent(leg))

    def _clear_legs(self):
        from shtoom.util import stack
        #print self, "clearing running legs %r"%(self.__legs.items())#,stack(8)
        for name, leg in self.__legs.items():
            leg._stopAudio()
            del self.__legs[name]

    _cleanup = _clear_legs

    def va_abort(self):
        self.mediaStop()
        self._clear_legs()
        self._triggerEvent(CallEndedEvent(None))

    def mediaPlay(self, playlist, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        leg.mediaPlay(playlist)

    def mediaRecord(self, dest, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        leg.mediaRecord(dest)

    def mediaStop(self, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        if leg is not None:
            leg.mediaStop()

    def mediaStopRecording(self, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        if leg is not None:
            leg.mediaStopRecording()

    def setTimer(self, delay):
        return Timer(self, delay)

    def isPlaying(self, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        return leg.isPlaying()

    def isRecording(self, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        return leg.isRecording()

    def dtmfMode(self, single=False, inband=False, timeout=0, leg=None):
        if leg is None:
            leg = self.getDefaultLeg()
        leg.dtmfMode(single, inband, timeout)

    def placeCall(self, toURI, fromURI=None):
        from shtoom.doug.leg import Leg
        nleg = Leg(cookie=None, dialog=None, voiceapp=self)
        self.__appl.placeCall(self.__cookie, nleg, toURI, fromURI)

    def va_hangupCall(self, cookie):
        self.__appl.dropCall(cookie)

    def connectLegs(self, leg1, leg2=None):
        from shtoom.doug.leg import Bridge

        if leg2 is None:
            leg2 = self.getDefaultLeg()
        if leg1 is leg2:
            raise ValueError, "can't join %r to itself!" % (leg1)
        else:
            b = Bridge(leg1, leg2)
            return b

    def sendDTMF(self, digits, cookie=None, duration=0.1, delay=0.05):
        "Send a string of DTMF keystrokes"
        for n, key in enumerate(digits):
            if key not in ',01234567890#*':
                raise ValueError, key
            if key == ',':
                # pause
                continue
            n = float(n)  # just in case
            if cookie is None:
                cookie = self.__cookie
            i = 0.2
            reactor.callLater(i + n * (duration + delay),
                              lambda k=key: self.__appl.startDTMF(cookie, k))
            reactor.callLater(i + n * (duration + delay) + duration,
                              lambda k=key: self.__appl.stopDTMF(cookie, k))

    def _inboundDTMFKeyPress(self, dtmf):
        if self.__dtmfSingleMode:
            self._triggerEvent(DTMFReceivedEvent(dtmf, self))
        else:
            self.__collectedDTMFKeys += dtmf
            if dtmf in ('#', '*'):
                dtmf, self.__collectedDTMFKeys = self.__collectedDTMFKeys, ''
                self._triggerEvent(DTMFReceivedEvent(dtmf, self))

    def va_startDTMFevent(self, dtmf, cookie=None):
        c = self.__currentDTMFKey
        if dtmf:
            if c is not dtmf:
                self.va_stopDTMFevent(c)
                self.__currentDTMFKey = dtmf
                self._inboundDTMFKeyPress(dtmf)
            else:
                # repeat
                pass

    def va_stopDTMFevent(self, dtmf, cookie=None):
        # For now, I only care about dtmf start events
        if dtmf == self.__currentDTMFKey:
            self.__currentDTMFKey = None