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 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)
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)
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)