aboutsummaryrefslogtreecommitdiffstats
path: root/gsm_call_fsm.py
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2015-12-01 23:48:54 +0100
committerHarald Welte <laforge@gnumonks.org>2015-12-01 23:53:45 +0100
commit3d058cf6579923e2864ca2bd55f0a4cd41f0ea54 (patch)
treecf481ab800219f6d9d9481831837501094b006fb /gsm_call_fsm.py
parent5b4c297ad99bb1e4ac0129567a39a6d3df695f9c (diff)
gsm_call_fsm: Connect the RTP streams of the two call legs
Diffstat (limited to 'gsm_call_fsm.py')
-rw-r--r--gsm_call_fsm.py88
1 files changed, 76 insertions, 12 deletions
diff --git a/gsm_call_fsm.py b/gsm_call_fsm.py
index 267d2b4..e4d697a 100644
--- a/gsm_call_fsm.py
+++ b/gsm_call_fsm.py
@@ -7,6 +7,10 @@ import pykka
from fysom import Fysom
from mncc_sock import mncc_msg, mncc_number, mncc_rtp_msg
+class RtpEndpointData(object):
+ def __init__(self):
+ self.ip = self.port = self.payload_type = self.payload_msg_type = None
+
class GsmCallFsm(pykka.ThreadingActor):
last_callref = 0
@@ -31,6 +35,11 @@ class GsmCallFsm(pykka.ThreadingActor):
# CC-CONNECT-ACK to be sent to MS
msg = mncc_msg(msg_type = mncc.MNCC_SETUP_COMPL_REQ, callref = self.callref)
self.mncc_ref.tell({'type': 'send', 'msg': msg})
+ # ask to create the RTP socket in RTP bridge mode
+ if self.rtp_bridge:
+ msg = mncc_rtp_msg(msg_type = mncc.MNCC_RTP_CREATE, callref = self.callref)
+ self.mncc_ref.tell({'type': 'send', 'msg': msg})
+ # directly transition into the ACTIVE state
self.fsm.mncc_setup_compl_req()
def _onmncc_disc_ind(self, e):
@@ -42,11 +51,13 @@ class GsmCallFsm(pykka.ThreadingActor):
if e.event != 'startup':
self.stop()
- def __init__(self, mncc_ref, ctrl_ref = None):
+ def __init__(self, mncc_ref, ctrl_ref = None, rtp_bridge = True):
super(GsmCallFsm, self).__init__()
self.mncc_ref = mncc_ref;
self.callref = self._get_next_callref()
self.ctrl_ref = ctrl_ref
+ self.rtp_bridge = rtp_bridge
+ self.rtp = None
self.fsm = Fysom(initial = 'NULL',
events = [
# MT call setup
@@ -87,7 +98,7 @@ class GsmCallFsm(pykka.ThreadingActor):
('mncc_rel_ind', '*', 'NULL'),
('mncc_disc_ind', 'DISCONNECT_INDICATION', 'RELEASE_REQUEST'),
- ('mncc_rel_cnf', 'RELEASE_REQUEST', 'NULL')
+ ('mncc_rel_cnf', 'RELEASE_REQUEST', 'NULL'),
],
callbacks = [('onmncc_setup_req', self._onmncc_setup_req),
('onmncc_setup_cnf', self._onmncc_setup_cnf),
@@ -102,6 +113,11 @@ class GsmCallFsm(pykka.ThreadingActor):
self.called = called
self.fsm.mncc_setup_req()
+ def connect_rtp(self, rtp):
+ rtp.msg_type = mncc.MNCC_RTP_CONNECT
+ rtp.callref = self.callref
+ self.mncc_ref.tell({'type': 'send', 'msg': rtp})
+
# MT call
def _do_mncc_rel_ind(self, mncc_msg):
self.fsm.mncc_rel_ind(mncc_msg)
@@ -126,6 +142,22 @@ class GsmCallFsm(pykka.ThreadingActor):
def _do_mncc_rel_cnf(self, mncc_msg):
self.fsm.mncc_rel_cnf(mncc_msg)
+ # RTP
+ def _do_mncc_rtp_create_ind(self, mncc_msg):
+ if self.rtp_bridge == False:
+ raise Exception('GsmCallFsm', 'rtp_create_ind but not in RTP bridge mode')
+ self.rtp = mncc_msg
+ # notify the call controller about this
+ self.ctrl_ref.tell({'type':'rtp_create_ind', 'called':self.called, 'rtp':self.rtp})
+
+ def _do_mncc_rtp_connect_ind(self, mncc_msg):
+ # FIXME
+ return
+
+ def _do_mncc_rtp_free_ind(self, mncc_msg):
+ # FIXME
+ return
+
_func_by_type = {
# MT call
mncc.MNCC_REL_IND: _do_mncc_rel_ind,
@@ -141,6 +173,11 @@ class GsmCallFsm(pykka.ThreadingActor):
mncc.MNCC_DISC_IND: _do_mncc_disc_ind,
mncc.MNCC_REL_IND: _do_mncc_rel_ind,
mncc.MNCC_REL_CNF: _do_mncc_rel_cnf,
+
+ # RTP
+ mncc.MNCC_RTP_CREATE: _do_mncc_rtp_create_ind,
+ mncc.MNCC_RTP_CONNECT: _do_mncc_rtp_connect_ind,
+ mncc.MNCC_RTP_FREE: _do_mncc_rtp_free_ind,
}
def _lookup_method(self, mncc_msg_type):
@@ -155,40 +192,67 @@ class GsmCallFsm(pykka.ThreadingActor):
def on_receive(self, message):
if message['type'] == 'mncc':
msg = message['msg']
- print 'GsmCallFsm(%u):on_receive(mncc, %s)' % (self.callref, msg)
if msg.callref == self.callref:
+ print 'GsmCallFsm(%u):on_receive(mncc, %s)' % (self.callref, msg)
return self._handle_mncc(msg)
elif message['type'] == 'start_mt_call':
self.start_mt_call(message['calling'], message['called'])
+ elif message['type'] == 'connect_rtp':
+ self.connect_rtp(message['rtp'])
else:
raise Exception('mncc', 'Unknown message %s' % message)
class GsmCallConnector(pykka.ThreadingActor):
- def __init__(self, mncc_act):
+ def __init__(self, mncc_act, rtp_bridge = True):
super(GsmCallConnector, self).__init__()
self.mncc_act = mncc_act
+ self.rtp_bridge = rtp_bridge
print 'Starting Call A actor'
- self.call_a = GsmCallFsm.start(self.mncc_act, self.actor_ref)
+ self.call_a = GsmCallFsm.start(self.mncc_act, self.actor_ref, self.rtp_bridge)
print 'Starting Call B actor'
- self.call_b = GsmCallFsm.start(self.mncc_act, self.actor_ref)
+ self.call_b = GsmCallFsm.start(self.mncc_act, self.actor_ref, self.rtp_bridge)
+ self.state_a = self_state_b = 'NULL'
+ self.rtp_a = self.rtp_b = None
def start_call_ab(self, msisdn_a, msisdn_b):
print 'Starting calls for A and B'
self.msisdn_a = msisdn_a
self.msisdn_b = msisdn_b
- # start MT call A->B
- print 'Starting Call A->B'
- self.call_a.tell({'type':'start_mt_call', 'calling':self.msisdn_a, 'called':self.msisdn_b})
-
# start MT call B->A
- print 'Starting Call B->A'
- self.call_b.tell({'type':'start_mt_call', 'calling':self.msisdn_b, 'called':self.msisdn_a})
+ print 'Starting MT Call to A'
+ self.call_a.tell({'type':'start_mt_call', 'calling':self.msisdn_b, 'called':self.msisdn_a})
+
+ # start MT call A->B
+ print 'Starting Call to B'
+ self.call_b.tell({'type':'start_mt_call', 'calling':self.msisdn_a, 'called':self.msisdn_b})
+
+ def rtp_created(self, msisdn, rtp):
+ print 'CallConnector:rtp_created(%s) %s' % (msisdn, rtp)
+ if self.rtp_bridge == False:
+ raise Exception('GsmCallConnector', 'rtp_created but not in RTP bridge mode')
+ if msisdn == self.msisdn_a: # A->B leg
+ self.rtp_a = rtp
+ elif msisdn == self.msisdn_b: # B->A leg
+ self.rtp_b = rtp
+ if self.rtp_a and self.rtp_b:
+ self.call_a.tell({'type':'connect_rtp', 'rtp':self.rtp_b})
+ self.call_b.tell({'type':'connect_rtp', 'rtp':self.rtp_a})
def call_state_change(self, msisdn, old_state, new_state):
print 'CallConnector:leg_state_change(%s) %s -> %s' % (msisdn, old_state, new_state)
+ if msisdn == self.msisdn_a: # A->B leg
+ self.state_a = new_state
+ elif msisdn == self.msisdn_b: # B->A leg
+ self.state_b = new_state
+ #if self.rtp_bridge == False and self.state_a == 'ACTIVE' and self.state_b == 'ACTIVE':
+ # self.connect_legs()
def on_receive(self, message):
if message['type'] == 'call_state_change':
self.call_state_change(message['called'], message['old_state'], message['new_state'])
+ elif message['type'] == 'rtp_create_ind':
+ self.rtp_created(message['called'], message['rtp'])
+ #else:
+ # raise Exception('mncc', 'GsmCallConnector Rx Unknown message %s' % message)