@@ -231,7 +231,7 @@ def __init__(self, sdp_info: SdpInfo) -> None:
231231
232232 def outgoing_call (
233233 self , source : SipEndpoint , destination : SipEndpoint , rtp_port : int
234- ):
234+ ) -> CallInfo :
235235 """Make an outgoing call from the given source endpoint to the destination endpoint, using the rtp_port for the local RTP port of the call."""
236236 if self .transport is None :
237237 raise RuntimeError ("No transport available for outgoing call." )
@@ -289,6 +289,14 @@ def outgoing_call(
289289 (destination .host , destination .port ),
290290 )
291291
292+ return CallInfo (
293+ caller_endpoint = destination ,
294+ local_endpoint = source ,
295+ caller_rtp_port = rtp_port ,
296+ server_ip = source .host ,
297+ headers = {"call-id" : call_id },
298+ )
299+
292300 def hang_up (self , call_info : CallInfo ):
293301 """Hang up the call when finished"""
294302 if self .transport is None :
@@ -315,6 +323,33 @@ def hang_up(self, call_info: CallInfo):
315323 self ._end_outgoing_call (call_info .headers ["call-id" ])
316324 self .on_hangup (call_info )
317325
326+ def cancel_call (self , call_info : CallInfo ):
327+ """Cancel an outgoing call while it's still ringing."""
328+ if self .transport is None :
329+ raise RuntimeError ("No transport available for sending cancel." )
330+
331+ cancel_lines = [
332+ f"CANCEL { call_info .caller_endpoint .uri } SIP/2.0" ,
333+ f"Via: SIP/2.0/UDP { call_info .local_endpoint .host } :{ call_info .local_endpoint .port } " ,
334+ f"From: { call_info .local_endpoint .sip_header } " ,
335+ f"To: { call_info .caller_endpoint .sip_header } " ,
336+ f"Call-ID: { call_info .headers ['call-id' ]} " ,
337+ "CSeq: 51 CANCEL" ,
338+ f"User-Agent: { VOIP_UTILS_AGENT } 1.0" ,
339+ "Content-Length: 0" ,
340+ "" ,
341+ ]
342+ _LOGGER .debug ("Canceling call..." )
343+ cancel_text = _CRLF .join (cancel_lines ) + _CRLF
344+ cancel_bytes = cancel_text .encode ("utf-8" )
345+ self .transport .sendto (
346+ cancel_bytes ,
347+ (call_info .caller_endpoint .host , call_info .caller_endpoint .port ),
348+ )
349+
350+ self ._end_outgoing_call (call_info .headers ["call-id" ])
351+ self .on_hangup (call_info )
352+
318353 def _register_outgoing_call (self , call_id : str , rtp_port : int ):
319354 """Register the RTP port associated with an outgoing call."""
320355 self ._outgoing_calls [call_id ] = rtp_port
0 commit comments