Skip to content

Commit 1e9a028

Browse files
authored
Merge pull request #28 from home-assistant-libs/synesthesiam-20250128-cancel-call
Add cancel_call
2 parents ea326a4 + dfd5d16 commit 1e9a028

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.3.1
4+
5+
- Add cancel_call to stop ringing
6+
37
## 0.3.0
48

59
- Add support for outgoing calls (@jaminh)

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "voip-utils"
7-
version = "0.3.0"
7+
version = "0.3.1"
88
license = {text = "Apache-2.0"}
99
description = "Voice over IP Utilities"
1010
readme = "README.md"

voip_utils/sip.py

+36-1
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)