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
This commit is contained in:
parent
a5fce60121
commit
5b283e8942
|
@ -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…
Reference in New Issue