message.py :  » Web-Services » Shtoom » shtoom-0.2 » shtoom » app » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Services » Shtoom 
Shtoom » shtoom 0.2 » shtoom » app » message.py
# Copyright (C) 2004 Anthony Baxter

# The Message app. Accepts all calls, plays a message, then hangs up.

from shtoom.app.interfaces import Application
from shtoom.app.base import BaseApplication
from twisted.internet import defer
from twisted.python import log
from twisted.protocols import sip
from shtoom.exceptions import CallFailed
import sys

from shtoom.audio import FMT_PCMU,FMT_GSM,FMT_SPEEX,FMT_DVI4
from shtoom.audio.fileaudio import getFileAudio

from shtoom.app.base import STATE_NONE,STATE_SENDING,STATE_RECEIVING,STATE_BOTH,STATE_DONE

class Message(BaseApplication):
    __implements__ = ( Application, )
    startingState = STATE_SENDING 

    def __init__(self, ui=None, audio=None):
        # Mapping from callcookies to rtp object
        self._rtp = {}
        # Mapping from callcookies to call objects
        self._calls = {}
        self._pendingRTP = {}
        self._audios = {}
        self._dtmf = {}
        self._audioFormats = {}
        self._audioStates = {}

    def boot(self, options=None):
        from shtoom.opts import buildOptions
        if options is None:
            options = buildOptions(self)
        self.initOptions(options)
  if not self.getPref('logfile'):
            log.startLogging(sys.stdout)
        else:
            log.startLogging(open(self.getPref('logfile'), 'aU'))
        BaseApplication.boot(self)

    def start(self):
        "Start the application."
        from twisted.internet import reactor
        register_uri = self.getPref('register_uri')
        if register_uri is not None:
            d = self.sip.register()
            d.addCallback(log.err).addErrback(log.err)
        reactor.run()

    def acceptCall(self, call, **calldesc):
        print "acceptCall for %r"%calldesc

        calltype = calldesc.get('calltype')
        d = defer.Deferred()
        cookie = self.getCookie()
        self._calls[cookie] = call
  print "ACCEPTED", self._calls.keys()
        self.openAudioDevice(cookie)
        d.addCallback(lambda x: self._createRTP(cookie,
                                                calldesc['fromIP'],
                                                calldesc['withSTUN']))
        if calltype == 'outbound':
            # Outbound call, trigger the callback immediately
            d.callback('')
        elif calltype == 'inbound':
            # Otherwise we chain callbacks
            log.msg("accepting incoming call from %s"%calldesc['desc'])
            d.callback('ok')
        else:
            raise ValueError, "unknown call type %s"%(calltype)
        return cookie, d

    def _createRTP(self, cookie, fromIP, withSTUN):
        from shtoom.rtp import RTPProtocol
        rtp = RTPProtocol(self, cookie)
        self._rtp[cookie] = rtp
        d = rtp.createRTPSocket(fromIP,withSTUN)
        return d

    def openAudioDevice(self, callcookie):
        audio_in = self.getPref('audio_infile')
        self._audios[callcookie] = getFileAudio(audio_in, '/dev/null')
        self._dtmf[callcookie] = None
        self._audioStates[callcookie] = STATE_NONE

    def selectFormat(self, callcookie, rtpmap):
        print "RTP", rtpmap
        rtp =  self._rtp[callcookie]
        audio = self._audios.get(callcookie)
        for entry,desc in rtpmap:
            if entry == rtp.PT_pcmu:
                audio.selectFormat(FMT_PCMU)
                self._audioFormats[callcookie] = entry
                break
            elif entry == rtp.PT_gsm:
                audio.selectFormat(FMT_GSM)
                self._audioFormats[callcookie] = entry
                break
            else:
                raise ValueError, "couldn't set to %r"%entry
        else:
            raise ValueError, "no working formats"

    def getSDP(self, callcookie):
        from shtoom.multicast.SDP import SimpleSDP
        rtp =  self._rtp[callcookie]
        s = SimpleSDP()
        s.setPacketSize(160)
        addr = rtp.getVisibleAddress()
        s.setServerIP(addr[0])
        s.setLocalPort(addr[1])
        fmts = self._audios[callcookie].listFormats()
        if FMT_PCMU in fmts:
            s.addRtpMap('PCMU', 8000) # G711 ulaw
        if FMT_GSM in fmts:
            s.addRtpMap('GSM', 8000) # GSM 06.10
        if FMT_SPEEX in fmts:
            s.addRtpMap('speex', 8000, payload=110)
            #s.addRtpMap('speex', 16000, payload=111)
        if FMT_DVI4 in fmts:
            s.addRtpMap('DVI4', 8000)
            #s.addRtpMap('DVI4', 16000)
        s.addRtpMap('telephone-event', 8000, payload=101)
        return s

    def startCall(self, callcookie, remoteAddr, cb):
        self._audioStates[callcookie] = self.startingState 
        self._rtp[callcookie].startSendingAndReceiving(remoteAddr)
        log.msg("call %s connected"%callcookie)
        cb(callcookie)

    def endCall(self, callcookie, reason=''):
        log.msg("call %s disconnected"%callcookie, reason)
        rtp = self._rtp[callcookie]
        rtp.stopSendingAndReceiving()
        del self._rtp[callcookie]
        if self._calls.get(callcookie):
            del self._calls[callcookie]
        self.closeAudioDevice(callcookie)

    def closeAudioDevice(self, callcookie):
        del self._audioStates[callcookie]
        self._audios[callcookie].close()
        del self._audios[callcookie]
        del self._dtmf[callcookie]

    def startDTMF(self, key):
        print "GOT DTMF START %s"%(key)

    def stopDTMF(self, key):
        print "GOT DTMF END %s"%(key)

    def receiveRTP(self, callcookie, payloadType, payloadData):
        # Yuk. If we're answering, the other end sets the PT!
        # XXX tofix!
  if payloadType == 101:
            key = ord(payloadData[0])
            start = (ord(payloadData[1]) & 128) and True or False
            d = self._dtmf
            if start:
                if d[callcookie] is not None and d[callcookie] != key:
                    self.stopDTMF(d[callcookie])
                    d[callcookie] = None
                if d[callcookie] is None:
                    d[callcookie] = key
                    self.startDTMF(key)
            elif d[callcookie] == key:
                d[callcookie]  = None
                self.stopDTMF(key)
            return
        if not (self._audioStates[callcookie] & STATE_RECEIVING):
            return 
        fmt = None
        if payloadType == 0:
            fmt = FMT_PCMU
        elif payloadType == 3:
            fmt = FMT_GSM
        if fmt:
            try:
                self._audios[callcookie].write(payloadData, fmt)
            except IOError:
                pass
        elif payloadType in (13, 19):
            # comfort noise
            pass
        else:
            print "unexpected RTP PT %s len %d"%(rtpPTDict.get(payloadType,str(payloadType)), len(datagram))

    def giveRTP(self, callcookie):
        # Check that callcookie is the active call!
        if not (self._audioStates[callcookie] & STATE_SENDING):
            return None # XXX comfort noise??
        data = self._audios[callcookie].read()
        if not data:
            self.finishedAudio(callcookie)
        if data is None:
            return None
        return self._audioFormats[callcookie], data

    def finishedAudio(self, callcookie):
        if (self._audioStates[callcookie] != STATE_DONE):
    self.dropCall(callcookie)

    def placeCall(self, sipURL):
        return self.sip.placeCall(sipURL)

    def dropCall(self, cookie):
        self._audioStates[cookie] = STATE_DONE
        call = self._calls.get(cookie)
        if not call:
            log.err("Couldn't find cookie %s, have %r, %r, %r"%(cookie, self._calls.keys(), self._audios.keys(), self._audioFormats.keys()))
            return
        call.dropCall()

    def statusMessage(self, message):
        log.msg("STATUS: "+message)

    def debugMessage(self, message):
        log.msg(message)

    def appSpecificOptions(self, opts):
        import os.path

        from shtoom.Options import OptionGroup,StringOption,ChoiceOption
        app = OptionGroup('shtoom', 'Shtoom')
        app.addOption(StringOption('audio_infile','read audio from this file'))
        app.addOption(StringOption('logfile','log to this file'))
        opts.addGroup(app)
        opts.setOptsFile('.shmessagerc')

    def authCred(self, method, uri, realm='unknown', retry=False):
        "Place holder for now"
        user = self.getPref('register_authuser')
        passwd = self.getPref('register_authpasswd')
        if user is not None and passwd is not None and retry is False:
            return defer.succeed((self.getPref('register_authuser'), 
                                 self.getPref('register_authpasswd')))
        else:
            raise defer.fail(CallFailed("No auth available"))

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.