diff options
author | Harald Welte <laforge@gnumonks.org> | 2015-12-01 23:48:54 +0100 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2015-12-01 23:53:45 +0100 |
commit | 3d058cf6579923e2864ca2bd55f0a4cd41f0ea54 (patch) | |
tree | cf481ab800219f6d9d9481831837501094b006fb /gsm_call_fsm.py | |
parent | 5b4c297ad99bb1e4ac0129567a39a6d3df695f9c (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.py | 88 |
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) |