This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Pau Espin Pedrol gerrit-no-reply at lists.osmocom.orgPau Espin Pedrol has submitted this change and it was merged. Change subject: modem: Implement voice calls in modem and add voice suite ...................................................................... modem: Implement voice calls in modem and add voice suite Change-Id: Ib402effc830db293f27a877658894e454a93a606 --- M example/resources.conf M src/osmo_gsm_tester/ofono_client.py M src/osmo_gsm_tester/schema.py A suites/voice/mo_mt_call.py A suites/voice/suite.conf 5 files changed, 145 insertions(+), 3 deletions(-) Approvals: Pau Espin Pedrol: Looks good to me, approved Jenkins Builder: Verified diff --git a/example/resources.conf b/example/resources.conf index 3daf677..70c1c35 100644 --- a/example/resources.conf +++ b/example/resources.conf @@ -60,7 +60,7 @@ ki: '80A37E6FDEA931EAC92FFA5F671EFEAD' auth_algo: 'xor' ciphers: [a5_0, a5_1] - features: ['sms'] + features: ['sms', 'voice'] - label: sierra_2 path: '/sierra_2' @@ -68,7 +68,7 @@ ki: '00969E283349D354A8239E877F2E0866' auth_algo: 'xor' ciphers: [a5_0, a5_1] - features: ['sms'] + features: ['sms', 'voice'] - label: gobi_0 path: '/gobi_0' diff --git a/src/osmo_gsm_tester/ofono_client.py b/src/osmo_gsm_tester/ofono_client.py index e301ed6..66c0a79 100644 --- a/src/osmo_gsm_tester/ofono_client.py +++ b/src/osmo_gsm_tester/ofono_client.py @@ -37,6 +37,8 @@ I_MODEM = 'org.ofono.Modem' I_NETREG = 'org.ofono.NetworkRegistration' I_SMS = 'org.ofono.MessageManager' +I_CALLMGR = 'org.ofono.VoiceCallManager' +I_CALL = 'org.ofono.VoiceCall' # See https://github.com/intgr/ofono/blob/master/doc/network-api.txt#L78 NETREG_ST_REGISTERED = 'registered' @@ -338,11 +340,15 @@ self.sms_received_list = [] self.dbus = ModemDbusInteraction(self.path) self.register_attempts = 0 + self.call_list = [] # one Cancellable can handle several concurrent methods. self.cancellable = Gio.Cancellable.new() self.dbus.required_signals = { I_SMS: ( ('IncomingMessage', self._on_incoming_message), ), I_NETREG: ( ('PropertyChanged', self._on_netreg_property_changed), ), + I_CALLMGR: ( ('PropertyChanged', self._on_callmgr_property_changed), + ('CallAdded', self._on_callmgr_call_added), + ('CallRemoved', self._on_callmgr_call_removed), ), } self.dbus.watch_interfaces() @@ -558,6 +564,80 @@ return True return False + def call_id_list(self): + self.dbg('call_id_list: %r' % self.call_list) + return self.call_list + + def call_dial(self, to_msisdn_or_modem): + if isinstance(to_msisdn_or_modem, Modem): + to_msisdn = to_msisdn_or_modem.msisdn + else: + to_msisdn = str(to_msisdn_or_modem) + self.dbg('Dialing:', to_msisdn) + cmgr = self.dbus.interface(I_CALLMGR) + call_obj_path = cmgr.Dial(to_msisdn, 'default') + if call_obj_path not in self.call_list: + self.dbg('Adding %s to call list' % call_obj_path) + self.call_list.append(call_obj_path) + else: + self.dbg('Dial returned already existing call') + return call_obj_path + + def _find_call_msisdn_state(self, msisdn, state): + cmgr = self.dbus.interface(I_CALLMGR) + ret = cmgr.GetCalls() + for obj_path, props in ret: + if props['LineIdentification'] == msisdn and props['State'] == state: + return obj_path + return None + + def call_wait_incoming(self, caller_msisdn_or_modem, timeout=60): + if isinstance(caller_msisdn_or_modem, Modem): + caller_msisdn = caller_msisdn_or_modem.msisdn + else: + caller_msisdn = str(caller_msisdn_or_modem) + self.dbg('Waiting for incoming call from:', caller_msisdn) + event_loop.wait(self, lambda: self._find_call_msisdn_state(caller_msisdn, 'incoming') is not None, timeout=timeout) + return self._find_call_msisdn_state(caller_msisdn, 'incoming') + + def call_answer(self, call_id): + self.dbg('Answer call %s' % call_id) + assert self.call_state(call_id) == 'incoming' + call_dbus_obj = systembus_get(call_id) + call_dbus_obj.Answer() + + def call_hangup(self, call_id): + self.dbg('Hang up call %s' % call_id) + call_dbus_obj = systembus_get(call_id) + call_dbus_obj.Hangup() + + def call_is_active(self, call_id): + return self.call_state(call_id) == 'active' + + def call_state(self, call_id): + call_dbus_obj = systembus_get(call_id) + props = call_dbus_obj.GetProperties() + state = props.get('State') + self.dbg('call state: %s' % state) + return state + + def _on_callmgr_call_added(self, obj_path, properties): + self.dbg('%r.CallAdded() -> %s=%r' % (I_CALLMGR, obj_path, repr(properties))) + if obj_path not in self.call_list: + self.call_list.append(obj_path) + else: + self.dbg('Call already exists %r' % obj_path) + + def _on_callmgr_call_removed(self, obj_path): + self.dbg('%r.CallRemoved() -> %s' % (I_CALLMGR, obj_path)) + if obj_path in self.call_list: + self.call_list.remove(obj_path) + else: + self.dbg('Trying to remove non-existing call %r' % obj_path) + + def _on_callmgr_property_changed(self, name, value): + self.dbg('%r.PropertyChanged() -> %s=%s' % (I_CALLMGR, name, value)) + def info(self, keys=('Manufacturer', 'Model', 'Revision', 'Serial')): props = self.properties() return ', '.join(['%s: %r'%(k,props.get(k)) for k in keys]) diff --git a/src/osmo_gsm_tester/schema.py b/src/osmo_gsm_tester/schema.py index 6d5f7ad..9b142d3 100644 --- a/src/osmo_gsm_tester/schema.py +++ b/src/osmo_gsm_tester/schema.py @@ -82,7 +82,7 @@ raise ValueError('Unknown Cipher value: %r' % val) def modem_feature(val): - if val in ('sms', 'gprs', 'voicecall', 'ussd'): + if val in ('sms', 'gprs', 'voice', 'ussd'): return raise ValueError('Unknown Modem Feature: %r' % val) diff --git a/suites/voice/mo_mt_call.py b/suites/voice/mo_mt_call.py new file mode 100755 index 0000000..f426037 --- /dev/null +++ b/suites/voice/mo_mt_call.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.test import * + +hlr = suite.hlr() +bts = suite.bts() +mgcpgw = suite.mgcpgw(bts_ip=bts.remote_addr()) +msc = suite.msc(hlr, mgcpgw) +bsc = suite.bsc(msc) +stp = suite.stp() +ms_mo = suite.modem() +ms_mt = suite.modem() + +hlr.start() +stp.start() +msc.start() +mgcpgw.start() + +bsc.bts_add(bts) +bsc.start() + +bts.start() + +hlr.subscriber_add(ms_mo) +hlr.subscriber_add(ms_mt) + +ms_mo.connect(msc.mcc_mnc()) +ms_mt.connect(msc.mcc_mnc()) + +ms_mo.log_info() +ms_mt.log_info() + +print('waiting for modems to attach...') +wait(ms_mo.is_connected, msc.mcc_mnc()) +wait(ms_mt.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms_mo, ms_mt) + +assert len(ms_mo.call_id_list()) == 0 and len(ms_mt.call_id_list()) == 0 +mo_cid = ms_mo.call_dial(ms_mt) +mt_cid = ms_mt.call_wait_incoming(ms_mo) +print('dial success') + +assert not ms_mo.call_is_active(mo_cid) and not ms_mt.call_is_active(mt_cid) +ms_mt.call_answer(mt_cid) +wait(ms_mo.call_is_active, mo_cid) +wait(ms_mt.call_is_active, mt_cid) +print('answer success, call established and ongoing') + +sleep(5) # maintain the call active for 5 seconds + +assert ms_mo.call_is_active(mo_cid) and ms_mt.call_is_active(mt_cid) +ms_mt.call_hangup(mt_cid) +wait(lambda: len(ms_mo.call_id_list()) == 0 and len(ms_mt.call_id_list()) == 0) +print('hangup success') diff --git a/suites/voice/suite.conf b/suites/voice/suite.conf new file mode 100644 index 0000000..40d9f97 --- /dev/null +++ b/suites/voice/suite.conf @@ -0,0 +1,9 @@ +resources: + ip_address: + - times: 5 # msc, bsc, hlr, stp, mgw + bts: + - times: 1 + modem: + - times: 2 + features: + - voice -- To view, visit https://gerrit.osmocom.org/4150 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ib402effc830db293f27a877658894e454a93a606 Gerrit-PatchSet: 3 Gerrit-Project: osmo-gsm-tester Gerrit-Branch: master Gerrit-Owner: Pau Espin Pedrol <pespin at sysmocom.de> Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de> Gerrit-Reviewer: Pau Espin Pedrol <pespin at sysmocom.de>