Skip to content

Commit f27d5ab

Browse files
committed
Hook up notification socket mechanism to disconnect the call
if the media goes away.
1 parent a048efc commit f27d5ab

File tree

1 file changed

+56
-4
lines changed

1 file changed

+56
-4
lines changed

Sippy_SRS.py

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323

2424
from argparse import ArgumentParser
2525
from weakref import WeakSet
26-
from functools import partial
26+
from functools import partial, wraps
27+
from secrets import token_hex
28+
from urllib.parse import quote
2729

2830
from sippy.UA import UA
2931
from sippy.CCEvents import CCEventTry, CCEventConnect, CCEventFail
@@ -39,6 +41,7 @@
3941
from sippy.SdpBody import SdpBody
4042
from sippy.SipReason import SipReason
4143
from sippy.UI.Controller import UIController
44+
from sippy.CLIManager import CLIManager
4245

4346
class SRSParams:
4447
sippy_c = None
@@ -49,6 +52,7 @@ class SRSParams:
4952
rtpp_r_res = None
5053
rtpp_u_res = None
5154
sess_sdp = None
55+
rname = None
5256
body_tmpl = '\r\n'.join(('v=0', f'o={SdpOrigin()}',
5357
's=Sippy_SRS', 't=0 0'))
5458
def __init__(self, sippy_c, req):
@@ -58,6 +62,10 @@ def __init__(self, sippy_c, req):
5862
self.sess_sdp = []
5963
self.rtpp_r_res = []
6064
self.rtpp_u_res = {}
65+
self.rname = str(token_hex(16))
66+
67+
def get_rname(self, index):
68+
return f'{self.rname}_{index}'
6169

6270
class SRSFailure(CCEventFail):
6371
c2m = {488:'Not Acceptable Here',
@@ -68,22 +76,37 @@ def __init__(self, reason, code=488):
6876
self.reason = SipReason(protocol='SIP', cause=code,
6977
reason=reason)
7078

79+
def check_state_required(method):
80+
@wraps(method)
81+
def wrapper(self, *args, **kwargs):
82+
if not self.checkState():
83+
return
84+
return method(self, *args, **kwargs)
85+
return wrapper
86+
7187
class SippySRSUAS(UA):
88+
id = 0
7289
_p: SRSParams
7390
cId: 'SipCallId'
7491

7592
def __init__(self, sippy_c, req, sip_t):
93+
self.id = SippySRSUAS.id
94+
SippySRSUAS.id += 1
7695
self._p = SRSParams(sippy_c, req)
7796
super().__init__(sippy_c, self.outEvent, disc_cbs = (self.sess_term,))
7897
super().recvRequest(req, sip_t)
7998

99+
def checkState(self):
100+
return isinstance(self.state, (self.UasStateTrying, self.UasStateRinging))
101+
80102
def sess_term(self, ua, rtime, origin, result = 0):
81103
print('disconnected')
82104
self._p.rsess.delete()
83105
del self._p.rsess
84106
del self._p.sippy_c
85107
self._p = None
86108

109+
@check_state_required
87110
def rtp_legA_created(self, index, result, _):
88111
if result is None:
89112
return self.rtp_rec_created(None)
@@ -93,20 +116,24 @@ def rtp_legA_created(self, index, result, _):
93116
up.result_callback = partial(self.rtp_legB_created, index)
94117
self._p.rsess.callee.update(up)
95118

119+
@check_state_required
96120
def rtp_legB_created(self, index, result, _):
97121
if result is None:
98122
return self.rtp_rec_created(None)
99123
self._p.rtpp_u_res[index] = (result.rtpproxy_address, result.rtpproxy_port)
100-
self._p.rsess.start_recording(result_callback=self.rtp_rec_created, index=index)
124+
rname = self._p.get_rname(index)
125+
self._p.rsess.start_recording(rname, result_callback=self.rtp_rec_created,
126+
index=index, only_a=True, rflags='s')
101127

128+
@check_state_required
102129
def rtp_rec_created(self, result):
103130
self._p.rtpp_r_res.append(result)
104131
if len(self._p.rtpp_r_res) < len(self._p.sess_sdp):
105132
return
106133
nerrs = sum([1 if r is None or r.startswith('E') else 0
107134
for r in self._p.rtpp_r_res])
108135
if nerrs > 0:
109-
fail = SRSFailure(f'Just Can\'t, {nerrs} times', 502)
136+
fail = SRSFailure(f'Something broke, {nerrs} times', 502)
110137
self.recvEvent(fail)
111138
return
112139
ah_pass = ('label', 'rtpmap', 'ptime')
@@ -124,6 +151,7 @@ def rtp_rec_created(self, result):
124151
event = CCEventConnect((200, 'OpenSIPIt Is Great Again! :)', sdp))
125152
self.recvEvent(event)
126153

154+
@check_state_required
127155
def outEvent(self, event, ua):
128156
if not isinstance(event, CCEventTry):
129157
return
@@ -142,6 +170,7 @@ def outEvent(self, event, ua):
142170
return
143171
#print(type(sdp_body.content), type(sdp_body.content.sections))
144172
rs = Rtp_proxy_session(self._p.sippy_c, cId, self._p.from_tag, self._p.to_tag)
173+
rs.notify_tag = quote(f'r {self.id}')
145174
self._p.rsess = rs
146175
rs.caller.raddress = self._p.source
147176
for sdp in sdps:
@@ -184,7 +213,8 @@ def __init__(self):
184213
UIController(sippy_c, "Sippy SIP Recording Server")
185214
udsc, udsoc = SipTransactionManager.model_udp_server
186215
udsoc.nworkers = 1
187-
rpc = Rtp_proxy_client(sippy_c, spath = args.rtp_proxy_client)
216+
kwa = {'nsetup_f': self.set_rtp_io_socket} if args.rtp_proxy_client.startswith('rtp.io:') else {}
217+
rpc = Rtp_proxy_client(sippy_c, spath = args.rtp_proxy_client, **kwa)
188218
def waitonline(_rpc):
189219
if _rpc.online:
190220
ED2.breakLoop()
@@ -230,5 +260,27 @@ def safeStop(self, signum=None):
230260
self.sippy_c['_sip_tm'].shutdown()
231261
Timeout(ED2.breakLoop, 0.2, 1)
232262

263+
def set_rtp_io_socket(self, rtpp_nsock, rtpp_nsock_spec):
264+
CLIManager(rtpp_nsock, self.recvCommand)
265+
266+
def recvCommand(self, clim, cmd):
267+
args = cmd.split()
268+
cmd = args.pop(0).lower()
269+
if cmd == 'r':
270+
if len(args) != 1:
271+
clim.send('ERROR: syntax error: r [<id>]\n')
272+
return False
273+
idx = int(args[0])
274+
dlist = tuple(x for x in self.active_uas if x.id == idx)
275+
if len(dlist) == 0:
276+
clim.send('ERROR: no call with id of %d has been found\n' % idx)
277+
return False
278+
for cc in dlist:
279+
cc.disconnect()
280+
clim.send('OK\n')
281+
return False
282+
clim.send('ERROR: unknown command\n')
283+
return False
284+
233285
if __name__ == '__main__':
234286
exit(SippySRS_Control().run())

0 commit comments

Comments
 (0)