My favorites | Sign in
Project Logo
                
Search
for
Updated Feb 27, 2009 by egghunt
Labels: Phase-Implementation, Phase-Support
InboundOutboundExample  

This example shows how to create a full-featured application to connect in the Inbound Socket and originate calls that will be controlled by the Outbound Socket.

It's easy and simple, just follow the code and be happy.

Source Code

#!/usr/bin/env python
# coding: utf-8
# freeswitch's event socket protocol for twisted
# Copyright (C) 2009  Alexandre Fiori & Arnaldo Pereira
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program 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 General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

from Queue import Queue
from eventsocket import EventProtocol
from twisted.internet import reactor, protocol

port = 1905
unique_id = {}

class InboundProxy(EventProtocol):
    def __init__(self):
	self.job_uuid = {}
	self.calls = Queue()
	EventProtocol.__init__(self)

    def authSuccess(self, ev):
	self.eventplain('CHANNEL_HANGUP BACKGROUND_JOB')

    def authFailure(self, failure):
	self.factory.reconnect = False

    def eventplainSuccess(self, ev):
	for ext in ['1000', '1001', '1002']:
	    self.calls.put(ext)
	    print '[inboundproxy] originating call to extension %s' % ext

            # FreeSWITCH will park the call immediately if the destination is socket().
            # when we receive this call on the outbound side, there won't be an ANSWER
            # nor a PARK event we can watch; hence, we must start processing right away.
	    self.bgapi("originate sofia/internal/%s%%192.168.0.3 '&socket(127.0.0.1:%d async full)'" % (ext, port))

    def eventplainFailure(self, failure):
	self.factory.reconnect = False
	self.exit()

    def bgapiSuccess(self, ev):
	ext = self.calls.get()
	self.calls.task_done()
	self.job_uuid[ev.Job_UUID] = ext

    def bgapiFailure(self, failure):
	print '[inboundproxy] bgapi failure: %s' % failure.value
	self.exit()

    def onBackgroundJob(self, data):
	ext = self.job_uuid[data.Job_UUID]
	del self.job_uuid[data.Job_UUID]
	response, content = data.rawresponse.split()
	if response == '+OK': unique_id[content] = ext
	else: print '[inboundproxy] cannot call %s: %s' % (ext, content)

    def onChannelHangup(self, data):
	if unique_id.has_key(data.Unique_ID):
	    ext = unique_id[data.Unique_ID]
	    del unique_id[data.Unique_ID]
	    print '[inboundproxy] extension %s hung up: %s' % (ext, data.Hangup_Cause)

class InboundFactory(protocol.ClientFactory):
    protocol = InboundProxy

    def __init__(self, password):
	self.password = password
	self.reconnect = True

    def clientConnectionLost(self, connector, reason):
	if self.reconnect: connector.connect()
	else:
	    print '[inboundfactory] stopping reactor'
	    reactor.stop()

    def clientConnectionFailed(self, connector, reason):
	print '[inboundfactoy] cannot connect: %s' % reason
	reactor.stop()

class OutboundProxy(EventProtocol):
    def __init__(self):
	self.ext = None
	self.debug_enabled = False
	EventProtocol.__init__(self)

    # when we get connection from fs, send "connect"
    def connectionMade(self):
	self.connect()

    # when we get OK from connect, send "myevents"
    def connectSuccess(self, ev):
	self.ext = unique_id[ev.Unique_ID]
	print '[outboundproxy] started controlling extension %s' % self.ext
	self.myevents()

    # after we get OK for myevents, send "answer".
    def myeventsSuccess(self, ev):
        self.answer()

    # when we get OK from answer, play something. Note: on default FreeSWITCH
    # deployments, the sounds directory is usually /usr/local/freeswitch/sounds
    def answerSuccess(self, ev):
	print '[outboundproxy] going to play audio file for extension %s' % self.ext
	self.playback('/opt/freeswitch/sounds/en/us/callie/ivr/8000/ivr-sample_submenu.wav',
	    terminators='123*#')

    # well well...
    def onDtmf(self, data):
	print '[outboundproxy] got dtmf "%s" from extension %s' % (data.DTMF_Digit, self.ext)

    # finished executing something
    def onChannelExecuteComplete(self, data):
	app = data.variable_current_application
	if app == 'playback':
	    terminator = data.get('variable_playback_terminator_used')
            response = data.get('variable_current_application_response')
	    print '[outboundproxy] extension %s finished playing file, terminator=%s, response=%s' % (self.ext, terminator, response)
	    print '[outboundproxy] bridging extension %s to public conference 888' % self.ext
	    self.bridge('sofia/external/888@conference.freeswitch.org')

	# it could also be done by onChannelUnbridge
	elif app == 'bridge':
	    print '[outboundproxy] extension %s finished the bridge' % self.ext
	    self.hangup()
    
    # goodbye...
    def exitSuccess(self, ev):
	print '[outboundproxy] control of extension %s has finished' % self.ext

class OutboundFactory(protocol.ServerFactory):
    protocol = OutboundProxy

if __name__ == '__main__':
    reactor.listenTCP(port, OutboundFactory())
    reactor.connectTCP('localhost', 8021, InboundFactory('ClueCon'))
    reactor.run()

Sign in to add a comment
Hosted by Google Code