Exemplo n.º 1
0
 def testDougConverter(self):
     ae = self.assertEqual
     d = DougConverter(device=DummyDev())
     d.selectDefaultFormat([
         PT_RAW,
     ])
     ae(d.getFormat(), PT_RAW)
     test = b'froooooooooooogle'
     p = RTPPacket(0, 0, 0, data=test, ct=PT_RAW)
     ae(d.convertInbound(p), test)
Exemplo n.º 2
0
class Leg(object):

    _dialog = None
    _cookie = None
    _acceptDeferred = None
    _voiceapp = None

    def __init__(self, cookie, dialog, voiceapp=None):
        """ Create a new leg
        """
        self._cookie = cookie
        self._dialog = dialog
        self._acceptDeferred = None
        self.__converter = DougConverter()
        self.__playoutList = []
        self.__silenceSource = SilenceSource()
        self.__connected = None
        self.__sink = None
        self.__currentDTMFKey = None
        self.__collectedDTMFKeys = ''
        self.__dtmfSingleMode = True
        self.__inbandDTMFdetector = None
        self._voiceapp = voiceapp
        self._connectSource(self.__silenceSource)
        self._startAudio()

    def _startAudio(self):
        #print(self, "starting audio")
        self.LC = LoopingCall(self._get_some_audio)
        self.LC.start(0.020)

    def _stopAudio(self):
        if self.LC is not None:
            #print(self, "stopping audio", self.LC, self.LC.call)
            self.LC.stop()
            self.LC = None

    def _get_some_audio(self):
        if self._voiceapp is not None:
            data = self.__connected.read()
            sample = self.__converter.convertOutbound(data)
            self._voiceapp.va_outgoingRTP(sample, self._cookie)

    def getDialog(self):
        return self._dialog

    def getCookie(self):
        return self._cookie

    def setDialog(self, dialog):
        self._dialog = dialog

    def setCookie(self, cookie):
        self._cookie = cookie

    def incomingCall(self, d):
        " This leg is an incoming call "
        self._acceptDeferred = d

    def outgoingCall(self):
        " This leg is an outgoing call "
        pass

    def getVoiceApp(self):
        "Get the VoiceApp currently connected to this leg"
        return self._voiceapp

    def hijackLeg(self, voiceapp):
        """ Remove the currently running VoiceApp from the leg, and
            slot in a new one. Returns the hijacked app.
        """
        old, self._voiceapp = self._voiceapp, voiceapp
        return old

    def callAnswered(self, voiceapp):
        "Called when an outbound call is answered"
        self._voiceapp = voiceapp
        voiceapp._triggerEvent(CallAnsweredEvent(self))

    def callRejected(self, voiceapp):
        "Called when an outbound call is rejected"
        self._voiceapp = voiceapp
        voiceapp._triggerEvent(CallRejectedEvent(self))

    def answerCall(self, voiceapp):
        " Answer the (incoming) call on this leg "
        if self._acceptDeferred is not None:
            log.msg("%r answering this call" % (self, ), system="doug")
            self._voiceapp = voiceapp
            d, self._acceptDeferred = self._acceptDeferred, None
            d.callback(self._cookie)
        else:
            log.msg("can't answer call %s, already answered/rejected" %
                    (self._cookie),
                    system='doug')

    def rejectCall(self, reason):
        " Reject the (incoming) call on this leg "
        if self._acceptDeferred is not None:
            d, self._acceptDeferred = self._acceptDeferred, None
            self._voiceapp = None
            self._cookie = None
            d.errback(reason)
        else:
            log.msg("can't reject call %s, already answered/rejected" %
                    (self._cookie),
                    system='doug')

    def hangupCall(self):
        self._stopAudio()
        if self._voiceapp:
            self._voiceapp.va_hangupCall(self._cookie)

    def sendDTMF(self, digits, duration=0.1, delay=0.05):
        self._voiceapp.sendDTMF(digits,
                                cookie=self._cookie,
                                duration=duration,
                                delay=delay)

    def _playNextItem(self):
        if not self.__playoutList:
            last = self._connectSource(self.__silenceSource)
            self._voiceapp._triggerEvent(MediaPlayContentDoneEvent(last, self))
        else:
            next = self.__playoutList.pop(0)
            next = convertToSource(next, 'r')
            self._connectSource(next)

    def _sourceDone(self, source):
        if self.__connected is source:
            self._playNextItem()

    def _connectSource(self, target):
        target.leg = self
        old, self.__connected = self.__connected, target
        if old:
            old.leg = None
        return old

    def _connectSink(self, target):
        if target:
            target.leg = self
        old, self.__sink = self.__sink, target
        if old:
            old.leg = None
        return old

    def _maybeStartPlaying(self):
        "Check if we're currently playing silence, and switch out if so"
        if self.__connected is self.__silenceSource:
            self._playNextItem()

    def mediaPlay(self, playlist):
        if isinstance(playlist, basestring):
            playlist = [playlist]
        self.__playoutList.extend(playlist)
        self._maybeStartPlaying()

    def mediaRecord(self, dest):
        dest = convertToSource(dest, 'w')
        self._connectSink(dest)

    def mediaStop(self):
        old = self._connectSource(self.__silenceSource)
        if old.isPlaying():
            old.close()
            self.__playoutList = []

    def mediaStopRecording(self):
        old = self._connectSink(None)
        if old and old.isRecording():
            old.close()

    def leg_startDTMFevent(self, dtmf):
        c = self.__currentDTMFKey
        if dtmf:
            if c is not dtmf:
                self.leg_stopDTMFevent(c)
                self.__currentDTMFKey = dtmf
                self._inboundDTMFKeyPress(dtmf)
            else:
                # repeat
                pass

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

    def selectDefaultFormat(self, ptlist):
        return self.__converter.selectDefaultFormat(ptlist)

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

    def set_handler(self, handler):
        self.__converter.set_handler(handler)

    def leg_incomingRTP(self, packet):
        data = self.__converter.convertInbound(packet)
        if self.__inbandDTMFdetector is not None:
            self.__inbandDTMFdetector(data)
        if self.__sink:
            self.__sink.write(data)

    def isPlaying(self):
        return self.__connected.isPlaying()

    def isRecording(self):
        return self.__sink and self.__sink.isRecording()

    def dtmfMode(self, single=False, inband=False, timeout=0):
        self.__dtmfSingleMode = single
        if inband:
            if numarray is None:
                raise RuntimeError("need numarray to do inband DTMF")
            else:
                self.__inbandDTMFdetector = InbandDtmfDetector(self)
        else:
            self.__inbandDTMFdetector = None
        # XXX handle timeout

    def __repr__(self):
        return '<Leg at %x connected to %r>' % (id(self), self._voiceapp)
Exemplo n.º 3
0
Arquivo: leg.py Projeto: braams/shtoom
class Leg(object):

    _dialog = None
    _cookie = None
    _acceptDeferred = None
    _voiceapp = None

    def __init__(self, cookie, dialog, voiceapp=None):
        """ Create a new leg
        """
        self._cookie = cookie
        self._dialog = dialog
        self._acceptDeferred = None
        self.__converter = DougConverter()
        self.__playoutList = []
        self.__silenceSource = SilenceSource()
        self.__connected = None
        self.__sink = None
        self.__currentDTMFKey = None
        self.__collectedDTMFKeys = ''
        self.__dtmfSingleMode = True
        self.__inbandDTMFdetector = None
        self._voiceapp = voiceapp
        self._connectSource(self.__silenceSource)
        self._startAudio()

    def _startAudio(self):
        #print self, "starting audio"
        self.LC = LoopingCall(self._get_some_audio)
        self.LC.start(0.020)

    def _stopAudio(self):
        if self.LC is not None:
            #print self, "stopping audio", self.LC, self.LC.call
            self.LC.stop()
            self.LC = None

    def _get_some_audio(self):
        if self._voiceapp is not None:
            data = self.__connected.read()
            sample = self.__converter.convertOutbound(data)
            self._voiceapp.va_outgoingRTP(sample, self._cookie)

    def getDialog(self):
        return self._dialog

    def getCookie(self):
        return self._cookie

    def setDialog(self, dialog):
        self._dialog = dialog

    def setCookie(self, cookie):
        self._cookie = cookie

    def incomingCall(self, d):
        " This leg is an incoming call "
        self._acceptDeferred = d

    def outgoingCall(self):
        " This leg is an outgoing call "
        pass

    def getVoiceApp(self):
        "Get the VoiceApp currently connected to this leg"
        return self._voiceapp

    def hijackLeg(self, voiceapp):
        """ Remove the currently running VoiceApp from the leg, and
            slot in a new one. Returns the hijacked app.
        """
        old, self._voiceapp = self._voiceapp, voiceapp
        return old

    def callAnswered(self, voiceapp):
        "Called when an outbound call is answered"
        self._voiceapp = voiceapp
        voiceapp._triggerEvent(CallAnsweredEvent(self))

    def callRejected(self, voiceapp):
        "Called when an outbound call is rejected"
        self._voiceapp = voiceapp
        voiceapp._triggerEvent(CallRejectedEvent(self))

    def answerCall(self, voiceapp):
        " Answer the (incoming) call on this leg "
        if self._acceptDeferred is not None:
            log.msg("%r answering this call"%(self,), system="doug")
            self._voiceapp = voiceapp
            d, self._acceptDeferred = self._acceptDeferred, None
            d.callback(self._cookie)
        else:
            log.msg("can't answer call %s, already answered/rejected"%(
                                                self._cookie), system='doug')

    def rejectCall(self, reason):
        " Reject the (incoming) call on this leg "
        if self._acceptDeferred is not None:
            d, self._acceptDeferred = self._acceptDeferred, None
            self._voiceapp = None
            self._cookie = None
            d.errback(reason)
        else:
            log.msg("can't reject call %s, already answered/rejected"%(
                                                self._cookie), system='doug')

    def hangupCall(self):
        self._stopAudio()
        if self._voiceapp:
            self._voiceapp.va_hangupCall(self._cookie)

    def sendDTMF(self, digits, duration=0.1, delay=0.05):
        self._voiceapp.sendDTMF(digits, cookie=self._cookie,
                                duration=duration, delay=delay)

    def _playNextItem(self):
        if not self.__playoutList:
            last = self._connectSource(self.__silenceSource)
            self._voiceapp._triggerEvent(MediaPlayContentDoneEvent(last, self))
        else:
            next = self.__playoutList.pop(0)
            next = convertToSource(next, 'r')
            self._connectSource(next)

    def _sourceDone(self, source):
        if self.__connected is source:
            self._playNextItem()

    def _connectSource(self, target):
        target.leg = self
        old, self.__connected = self.__connected, target
        if old:
            old.leg = None
        return old

    def _connectSink(self, target):
        if target:
            target.leg = self
        old, self.__sink = self.__sink, target
        if old:
            old.leg = None
        return old

    def _maybeStartPlaying(self):
        "Check if we're currently playing silence, and switch out if so"
        if self.__connected is self.__silenceSource:
            self._playNextItem()

    def mediaPlay(self, playlist):
        if isinstance(playlist, basestring):
            playlist = [playlist]
        self.__playoutList.extend(playlist)
        self._maybeStartPlaying()

    def mediaRecord(self, dest):
        dest = convertToSource(dest, 'w')
        self._connectSink(dest)

    def mediaStop(self):
        old = self._connectSource(self.__silenceSource)
        if old.isPlaying():
            old.close()
            self.__playoutList = []

    def mediaStopRecording(self):
        old = self._connectSink(None)
        if old and old.isRecording():
            old.close()

    def leg_startDTMFevent(self, dtmf):
        c = self.__currentDTMFKey
        if dtmf:
            if c is not dtmf:
                self.leg_stopDTMFevent(c)
                self.__currentDTMFKey = dtmf
                self._inboundDTMFKeyPress(dtmf)
            else:
                # repeat
                pass

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

    def selectDefaultFormat(self, ptlist):
        return self.__converter.selectDefaultFormat(ptlist)

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

    def set_handler(self, handler):
        self.__converter.set_handler(handler)

    def leg_incomingRTP(self, packet):
        data = self.__converter.convertInbound(packet)
        if self.__inbandDTMFdetector is not None:
            self.__inbandDTMFdetector(data)
        if self.__sink:
            self.__sink.write(data)

    def isPlaying(self):
        return self.__connected.isPlaying()

    def isRecording(self):
        return self.__sink and self.__sink.isRecording()

    def dtmfMode(self, single=False, inband=False, timeout=0):
        self.__dtmfSingleMode = single
        if inband:
            if numarray is None:
                raise RuntimeError, "need numarray to do inband DTMF"
            else:
                self.__inbandDTMFdetector = InbandDtmfDetector(self)
        else:
            self.__inbandDTMFdetector = None
        # XXX handle timeout

    def __repr__(self):
        return '<Leg at %x connected to %r>'%(id(self), self._voiceapp)