gcm_call_fsm: Allow user to specify which codec(s) are to be used

The user can submit a list of permitted codecs for a GsmCallFsm or
GsmCallConnector.  This list is ordered by priority (highest first),
and the first matching codec is chosen.

TODO: Proper error handling in case no matching codec is found
changes/71/1971/1
Harald Welte 7 years ago
parent a5fce60121
commit 5b283e8942
  1. 72
      gsm_call_fsm.py
  2. 6
      mncc_test.py

@ -18,6 +18,53 @@ from mncc_sock import mncc_msg, mncc_number, mncc_rtp_msg, mncc_bridge_msg
Uint32Array2 = mncc.uint32_t * 2
class GSM48:
class BCAP_SV(object):
# GSM 04.08 bearer capability speech version
FR = 0
HR = 1
EFR = 2
AMR_F = 4
AMR_H = 5
def __init__(self, codec):
self.codec = codec;
def __str__(self):
if self.codec == GSM48.BCAP_SV.FR:
return 'FR'
elif self.codec == GSM48.BCAP_SV.HR:
return 'HR'
elif self.codec == GSM48.BCAP_SV.EFR:
return 'EFR'
elif self.codec == GSM48.BCAP_SV.AMR_F:
return 'AMR-FR'
elif self.codec == GSM48.BCAP_SV.AMR_H:
return 'AMR-HR'
else:
return 'Unknown'
def to_lchan_mode(self):
if self.codec == GSM48.BCAP_SV.FR:
return GSM48.ChanMode.SPEECH_V1
elif self.codec == GSM48.BCAP_SV.HR:
return GSM48.ChanMode.SPEECH_V1
elif self.codec == GSM48.BCAP_SV.EFR:
return GSM48.ChanMode.SPEECH_EFR
elif self.codec == GSM48.BCAP_SV.AMR_F:
return GSM48.ChanMode.SPEECH_AMR
elif self.codec == GSM48.BCAP_SV.AMR_H:
return GSM48.ChanMode.SPEECH_AMR
AllCodecs = (BCAP_SV.FR, BCAP_SV.HR, BCAP_SV.EFR, BCAP_SV.AMR_F, BCAP_SV.AMR_H)
class ChanMode:
# GSM 04.08 Channel Mode
CMODE_SIGN = 0x00
SPEECH_V1 = 0x01
SPEECH_EFR = 0x21
SPEECH_AMR = 0x41
class GsmCallFsm(pykka.ThreadingActor):
last_callref = 0
@ -37,11 +84,20 @@ class GsmCallFsm(pykka.ThreadingActor):
called = mncc_number(self.called))
self.mncc_ref.tell({'type': 'send', 'msg': msg})
def find_matching_codec(self, ms_codecs):
# find common denominator of permitted codecs and MS codecs
for i in self.codecs_permitted:
if i in ms_codecs:
return GSM48.BCAP_SV(i)
return None
def _onmncc_call_conf_ind(self, e):
msg_in = e.args[0]
for i in msg_in.bearer_cap.speech_ver:
print 'SPV: 0x%02x' % i,
msg = mncc_msg(msg_type = mncc.MNCC_LCHAN_MODIFY, callref = msg_in.callref, lchan_mode = 1)
codec = self.find_matching_codec(msg_in.bearer_cap.speech_ver)
print 'CALL-CONF.ind(selected codec = %s)' % codec
# select the according lchan_mode
lchan_mode = codec.to_lchan_mode()
msg = mncc_msg(msg_type = mncc.MNCC_LCHAN_MODIFY, callref = msg_in.callref, lchan_mode = lchan_mode)
self.mncc_ref.tell({'type': 'send', 'msg': msg})
def _onmncc_setup_cnf(self, e):
@ -65,13 +121,14 @@ class GsmCallFsm(pykka.ThreadingActor):
if e.event != 'startup':
self.stop()
def __init__(self, mncc_ref, ctrl_ref = None, rtp_bridge = True):
def __init__(self, mncc_ref, ctrl_ref = None, rtp_bridge = True, codecs_permitted = GSM48.AllCodecs):
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.codecs_permitted = codecs_permitted
self.fsm = Fysom(initial = 'NULL',
events = [
# MT call setup
@ -221,14 +278,15 @@ class GsmCallFsm(pykka.ThreadingActor):
class GsmCallConnector(pykka.ThreadingActor):
def __init__(self, mncc_act, rtp_bridge = True):
def __init__(self, mncc_act, rtp_bridge = True, codecs_permitted = GSM48.AllCodecs):
super(GsmCallConnector, self).__init__()
self.mncc_act = mncc_act
self.rtp_bridge = rtp_bridge
self.codecs_permitted = codecs_permitted
print 'Starting Call A actor'
self.call_a = GsmCallFsm.start(self.mncc_act, self.actor_ref, self.rtp_bridge)
self.call_a = GsmCallFsm.start(self.mncc_act, self.actor_ref, self.rtp_bridge, self.codecs_permitted)
print 'Starting Call B actor'
self.call_b = GsmCallFsm.start(self.mncc_act, self.actor_ref, self.rtp_bridge)
self.call_b = GsmCallFsm.start(self.mncc_act, self.actor_ref, self.rtp_bridge, self.codecs_permitted)
self.callref_a = self.call_a.ask({'type':'get_callref'})
self.callref_b = self.call_b.ask({'type':'get_callref'})
self.state_a = self_state_b = 'NULL'

@ -9,7 +9,7 @@
# option, any later version.
from gsm_call_fsm import GsmCallFsm, GsmCallConnector
from gsm_call_fsm import GsmCallFsm, GsmCallConnector, GSM48
from mncc_sock import MnccSocket
from thread import start_new_thread
import pykka
@ -54,8 +54,8 @@ mncc_act = MnccActor.start(mncc_sock)
start_new_thread(mncc_rx_thread, (mncc_sock,))
# convenience wrapper
def connect_call(msisdn_a, msisdn_b):
call_conn = GsmCallConnector.start(mncc_act).proxy()
def connect_call(msisdn_a, msisdn_b, rtp_bridge = True, codecs = GSM48.AllCodecs):
call_conn = GsmCallConnector.start(mncc_act, rtp_bridge, codecs).proxy()
call_conn.start_call_ab(msisdn_a, msisdn_b)
return call_conn

Loading…
Cancel
Save