44import errno
55
66from rtpsynth .RtpServer import RtpQueueFullError , RtpServer
7- from sippy .misc import local4remote
87from sippy .Time .MonoTime import MonoTime
98
109from .Core .AudioChunk import AudioChunk
@@ -27,11 +26,12 @@ def __init__(self, rc:RTPConf, rtp_params:RTPParams, audio_in:callable,
2726 self .id = uuid4 ()
2827 self .rtp_params = rtp_params
2928 self .handlers = handlers or RTPHandlers ()
29+ self ._palloc = rc .palloc
3030 self ._rtp_server = None
3131 self .state_lock = Lock ()
3232 self .writer = None
3333 self .rsess = self .make_rtp_instream (rtp_params , audio_in )
34- rserv_opts = self .make_udp_server_opts (rc , rtp_params )
34+ rserv_opts = self .make_udp_server_opts (rtp_params )
3535 self .rserv = self .make_udp_server (rserv_opts )
3636 if self .rtp_params .rtp_target is not None :
3737 self .writer_setup ()
@@ -42,12 +42,9 @@ def make_writer(self, rtp_params:RTPParams):
4242 def make_rtp_instream (self , rtp_params :RTPParams , audio_in :callable ):
4343 return self .handlers .rtp_instream_cls (rtp_params , audio_in )
4444
45- def make_udp_server_opts (self , rc :RTPConf , rtp_params :RTPParams ):
46- if rtp_params .rtp_target is None :
47- rtp_laddr = '0.0.0.0'
48- else :
49- rtp_laddr = local4remote (rtp_params .rtp_target [0 ])
50- return (rtp_laddr , rc .palloc )
45+ def make_udp_server_opts (self , rtp_params :RTPParams ):
46+ palloc = self ._palloc if rtp_params .rtp_lport == 0 else rtp_params .rtp_lport
47+ return (rtp_params .rtp_laddr , palloc )
5148
5249 def make_udp_server (self , rserv_opts ):
5350 rtp_laddr , palloc = rserv_opts
@@ -56,30 +53,10 @@ def make_udp_server(self, rserv_opts):
5653 channel = None
5754 self ._rtp_server = rtp_server
5855 try :
59- if callable (palloc ):
60- ntry = - 1
61- while True :
62- ntry += 1
63- bind_port = int (palloc (ntry ))
64- try :
65- channel = rtp_server .create_channel (
66- pkt_in = self .rtp_received ,
67- bind_host = rtp_laddr ,
68- bind_port = bind_port ,
69- )
70- except OSError as ex :
71- if ex .errno == errno .EADDRINUSE :
72- continue
73- raise
74- break
75- else :
76- channel = rtp_server .create_channel (
77- pkt_in = self .rtp_received ,
78- bind_host = rtp_laddr ,
79- bind_port = int (palloc ),
80- )
81- if self .rtp_params .rtp_target is not None :
82- channel .set_target (self .rtp_params .rtp_target [0 ], self .rtp_params .rtp_target [1 ])
56+ channel = self ._bind_channel (rtp_server , rtp_laddr , palloc )
57+ target = self .rtp_params .rtp_target
58+ if target is not None :
59+ channel .set_target (target [0 ], target [1 ])
8360 return channel
8461 except Exception :
8562 release_rtp_server (rtp_server )
@@ -88,6 +65,51 @@ def make_udp_server(self, rserv_opts):
8865 channel .close ()
8966 raise
9067
68+ def _create_channel (self , rtp_server :RtpServer , bind_host :str , bind_port :int ):
69+ bind_family = self .rtp_params .rtp_family
70+ ch_kwargs = dict (pkt_in = self .rtp_received , bind_host = bind_host , bind_port = bind_port )
71+ ch = rtp_server .create_channel (bind_family = bind_family , ** ch_kwargs )
72+ self .rtp_params .rtp_lport = bind_port
73+ return ch
74+
75+ def _bind_channel (self , rtp_server :RtpServer , rtp_laddr :str , palloc , preferred_port :int = None ):
76+ if preferred_port is not None :
77+ try :
78+ return self ._create_channel (rtp_server , rtp_laddr , preferred_port )
79+ except OSError as ex :
80+ if ex .errno != errno .EADDRINUSE :
81+ raise
82+ if callable (palloc ):
83+ ntry = - 1
84+ while True :
85+ ntry += 1
86+ bind_port = int (palloc (ntry ))
87+ try :
88+ return self ._create_channel (rtp_server , rtp_laddr , bind_port )
89+ except OSError as ex :
90+ if ex .errno == errno .EADDRINUSE :
91+ continue
92+ raise
93+ return self ._create_channel (rtp_server , rtp_laddr , int (palloc ))
94+
95+ def _swap_channel (self , old_channel , rtp_params :RTPParams ):
96+ with self .state_lock :
97+ rtp_server = self ._rtp_server
98+ if rtp_server is None or self .rserv is not old_channel :
99+ return
100+ rtp_laddr , palloc = self .make_udp_server_opts (rtp_params )
101+ preferred_port = old_channel .local_addr [1 ]
102+ new_channel = self ._bind_channel (rtp_server , rtp_laddr , palloc , preferred_port = preferred_port )
103+ target = rtp_params .rtp_target
104+ if target is not None :
105+ new_channel .set_target (target [0 ], target [1 ])
106+ with self .state_lock :
107+ if self ._rtp_server is None or self .rserv is not old_channel :
108+ new_channel .close ()
109+ return
110+ self .rserv = new_channel
111+ old_channel .close ()
112+
91113 def writer_setup (self ):
92114 assert self .writer is None
93115 writer = self .make_writer (self .rtp_params )
@@ -124,8 +146,11 @@ def update(self, rtp_params:RTPParams):
124146 old_writer = None
125147 need_new_writer = False
126148 target_changed = False
149+ proto_changed = False
127150 with self .state_lock :
128151 target_changed = self .rtp_params .rtp_target != rtp_params .rtp_target
152+ proto_changed = self .rtp_params .rtp_proto != rtp_params .rtp_proto
153+ self .rtp_params .rtp_proto = rtp_params .rtp_proto
129154 self .rtp_params .rtp_target = rtp_params .rtp_target
130155 ptime_changed = self .rtp_params .out_ptime != rtp_params .out_ptime
131156 self .rtp_params .out_ptime = rtp_params .out_ptime
@@ -137,15 +162,18 @@ def update(self, rtp_params:RTPParams):
137162 self .writer = None
138163 elif self .writer is None :
139164 need_new_writer = True
140- elif ptime_changed :
165+ elif ptime_changed or proto_changed :
141166 old_writer = self .writer
142167 self .writer = None
143168 need_new_writer = True
144- if target_changed and channel is not None and self .rtp_params .rtp_target is not None :
145- channel .set_target (rtp_params .rtp_target [0 ], rtp_params .rtp_target [1 ])
146169 if old_writer is not None :
147170 old_writer .end ()
148171 old_writer .join ()
172+ if proto_changed and channel is not None :
173+ self ._swap_channel (channel , rtp_params )
174+ elif target_changed and channel is not None and self .rtp_params .rtp_target is not None :
175+ target = self .rtp_params .rtp_target
176+ channel .set_target (target [0 ], target [1 ])
149177 if need_new_writer :
150178 new_writer = self .make_writer (rtp_params )
151179 new_writer .set_pkt_send_f (self .send_pkt )
0 commit comments