-
Notifications
You must be signed in to change notification settings - Fork 120
improve timeout behavior #738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6761850
fd4f2f9
3e10827
e9895fa
753157a
7498d6f
69f1784
a5c394a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import Optional, Union | ||
|
|
||
| from livekit.protocol.connector_whatsapp import AcceptWhatsAppCallRequest | ||
| from livekit.protocol.sip import CreateSIPParticipantRequest, TransferSIPParticipantRequest | ||
|
|
||
| # Requests that carry wait_until_answered / ringing_timeout and share the | ||
| # phone-dialing timeout behavior. | ||
| DialRequest = Union[ | ||
| CreateSIPParticipantRequest, | ||
| TransferSIPParticipantRequest, | ||
| AcceptWhatsAppCallRequest, | ||
| ] | ||
| """@private""" | ||
|
|
||
| # Ring window (seconds) assumed when a request doesn't set ringing_timeout; | ||
| # matches the server default. A dialing request must outlast it. | ||
| DEFAULT_RINGING_TIMEOUT = 30.0 | ||
| """@private""" | ||
|
|
||
| # A dialing request must outlast the ringing window, or it would abort before | ||
| # the call can be answered. Keep the request timeout at least this many seconds | ||
| # above the ringing timeout. | ||
| RINGING_TIMEOUT_MARGIN = 2.0 | ||
| """@private""" | ||
|
|
||
|
|
||
| def pin_ringing_timeout(request: DialRequest) -> None: | ||
| """Set the ring window explicitly on a dialing request when the caller left it | ||
| unset, so the derived request timeout doesn't depend on the server's default | ||
| (which could change out from under us). | ||
|
|
||
| @private | ||
| """ | ||
| if not request.HasField("ringing_timeout"): | ||
| request.ringing_timeout.seconds = int(DEFAULT_RINGING_TIMEOUT) | ||
|
|
||
|
|
||
| def dial_timeout(user_timeout: Optional[float], request: DialRequest) -> float: | ||
| """Request timeout (seconds) for a phone-dialing call: the ring window plus a | ||
| margin, so the request doesn't abort before the call can be answered. The | ||
| ring window is the request's ringing_timeout when set, else | ||
| DEFAULT_RINGING_TIMEOUT. A longer user_timeout is honored; a shorter one is | ||
| raised to the floor. | ||
|
|
||
| @private | ||
| """ | ||
| if request.HasField("ringing_timeout"): | ||
| ring: float = request.ringing_timeout.seconds | ||
| else: | ||
| ring = DEFAULT_RINGING_TIMEOUT | ||
| floor = ring + RINGING_TIMEOUT_MARGIN | ||
| return max(user_timeout if user_timeout else floor, floor) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ | |
| SIPTransport, | ||
| ) | ||
| from ._service import Service | ||
| from ._dial_timeout import dial_timeout as _dial_timeout, pin_ringing_timeout as _pin_ringing_timeout | ||
| from .access_token import VideoGrants, SIPGrants | ||
|
|
||
| SVC = "SIP" | ||
|
|
@@ -781,17 +782,15 @@ async def create_sip_participant( | |
| SIPError: If the SIP operation fails | ||
| """ | ||
| client_timeout: Optional[aiohttp.ClientTimeout] = None | ||
| if timeout: | ||
| # obay user specified timeout | ||
| if create.wait_until_answered: | ||
| # Dialing a phone and waiting for an answer takes longer than a | ||
| # normal call, and the request must outlast ringing. Pin the ring | ||
| # window so the timeout doesn't depend on the server's default. | ||
| _pin_ringing_timeout(create) | ||
| client_timeout = aiohttp.ClientTimeout(total=_dial_timeout(timeout, create)) | ||
| elif timeout: | ||
| # obey user specified timeout | ||
| client_timeout = aiohttp.ClientTimeout(total=timeout) | ||
|
Comment on lines
+785
to
793
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: User-specified timeout is now overridden for wait_until_answered calls Previously in Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| elif create.wait_until_answered: | ||
| # ensure default timeout isn't too short when using sync mode | ||
| if ( | ||
| self._client._session.timeout | ||
| and self._client._session.timeout.total | ||
| and self._client._session.timeout.total < 20 | ||
| ): | ||
| client_timeout = aiohttp.ClientTimeout(total=20) | ||
|
|
||
| if trunk_id: | ||
| create.sip_trunk_id = trunk_id | ||
|
|
@@ -809,16 +808,27 @@ async def create_sip_participant( | |
| ) | ||
|
|
||
| async def transfer_sip_participant( | ||
| self, transfer: TransferSIPParticipantRequest | ||
| self, | ||
| transfer: TransferSIPParticipantRequest, | ||
| *, | ||
| timeout: Optional[float] = None, | ||
| ) -> SIPParticipantInfo: | ||
| """Transfer a SIP participant to a different room. | ||
|
|
||
| Args: | ||
| transfer: Request containing transfer details | ||
| timeout: Optional request timeout in seconds. Transferring dials a | ||
| phone, which takes longer than normal, so it defaults to a | ||
| longer timeout when unset. | ||
|
|
||
| Returns: | ||
| Updated SIP participant information | ||
| """ | ||
| # Transferring a call dials a phone, which takes longer than a normal | ||
| # call, so keep the request alive past ringing. Pin the ring window so the | ||
| # timeout doesn't depend on the server's default. | ||
| _pin_ringing_timeout(transfer) | ||
| client_timeout = aiohttp.ClientTimeout(total=_dial_timeout(timeout, transfer)) | ||
|
Comment on lines
+830
to
+831
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚩 transfer_sip_participant now always overrides timeout (behavioral change) Previously Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| return await self._client.request( | ||
| SVC, | ||
| "TransferSIPParticipant", | ||
|
|
@@ -831,6 +841,7 @@ async def transfer_sip_participant( | |
| sip=SIPGrants(call=True), | ||
| ), | ||
| SIPParticipantInfo, | ||
| timeout=client_timeout, | ||
| ) | ||
|
|
||
| def _admin_headers(self) -> dict[str, str]: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.