Skip to content

Address review comments: SRTP ROC tracking, RTP address selection, protocol hardening#24

Merged
codingjoe merged 2 commits intotranscribe-callfrom
copilot/sub-pr-8
Mar 13, 2026
Merged

Address review comments: SRTP ROC tracking, RTP address selection, protocol hardening#24
codingjoe merged 2 commits intotranscribe-callfrom
copilot/sub-pr-8

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 13, 2026

Addresses all unresolved review comments from the call transcription PR series.

SRTP (voip/srtp.py)

  • Separate send/receive ROC counters_send_roc/_last_send_seq for encryption, _recv_roc/_last_recv_seq for decryption, per RFC 3711 §3.3.1
  • Full index estimation on receive_estimate_recv_index() implements the RFC 3711 §3.3.1 algorithm (plain arithmetic comparisons, not modular)
  • Constant-time auth tag comparison — replaces != with hmac.compare_digest (stdlib) to prevent timing side-channels

SIP Protocol (voip/sip/protocol.py)

  • Remote RTP address selection — prefers media-level c= → session-level c= → SIP peer IP (per RFC 4566 §5.7); port 0 (inactive media, RFC 4566 §5.14) skips registration and NAT hole-punching
  • Early INVITE guard_initialize_task stored on connection_made; _answer() awaits it only when _rtp_protocol is still None, preventing attribute errors without breaking tests
  • Remove error_receivedasyncio.Protocol has no such callback (it belongs to DatagramProtocol); removed method and its tests

Audio (voip/audio.py)

  • WhisperModel injectionWhisperCall.model now accepts a pre-loaded WhisperModel instance in addition to a name string, enabling sharing across concurrent calls:
shared_model = WhisperModel("base")

class MyCall(WhisperCall):
    model = shared_model  # loaded once, reused per call

Docs / minor

  • STUN docstring — removed stale reference to public_address (attribute no longer exists on STUNProtocol)
  • RTP docstring — "silently discarded" → "logged at WARNING level and discarded" to match actual behavior
  • README — removed inaccurate "Unencrypted SIP or RTP is not supported" claim

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…ion, STUN docstring, WhisperModel injection, README cleanup

Co-authored-by: codingjoe <[email protected]>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 13, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 192.0.2.1
    • Triggering command: REDACTED, pid is -1 (packet block)
  • stun.cloudflare.com
    • Triggering command: /usr/bin/python python -m pytest tests/test_stun.py tests/test_rtp.py tests/sip/test_protocol.py -x -q --override-ini=addopts= (dns block)
    • Triggering command: /usr/bin/python python -m pytest tests/sip/test_protocol.py -x -q --override-ini=addopts= --no-header (dns block)
    • Triggering command: /usr/bin/python python -m pytest tests/sip/test_protocol.py::TestAnswer -x -q --override-ini=addopts= --no-header --tags --long --abbrev=40 git --gi�� (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title [WIP] Implement call transcription Address review comments: SRTP ROC tracking, RTP address selection, protocol hardening Mar 13, 2026
Copilot AI requested a review from codingjoe March 13, 2026 19:40
@codingjoe codingjoe marked this pull request as ready for review March 13, 2026 20:11
Copilot AI review requested due to automatic review settings March 13, 2026 20:11
@codingjoe codingjoe merged commit c4d53cf into transcribe-call Mar 13, 2026
1 check failed
@codingjoe codingjoe deleted the copilot/sub-pr-8 branch March 13, 2026 20:11
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens core VoIP call handling by refining SRTP rollover/index tracking, improving SIP call-answer robustness and SDP-derived RTP routing decisions, and aligning docs/tests with actual runtime behavior.

Changes:

  • SRTP: split send/receive ROC tracking, implement RFC 3711 receive index estimation, and use constant-time auth-tag comparison.
  • SIP: add early-INVITE initialization guard, improve remote RTP address selection per RFC 4566 (including inactive port 0), and remove the non-existent asyncio.Protocol.error_received.
  • Audio/docs/tests: allow injecting a pre-loaded WhisperModel, update docstrings/tests/logging text, and adjust README claims.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
voip/stun.py Updates STUNProtocol docstring to reflect current callback-based readiness API.
voip/srtp.py Refactors ROC tracking, adds receive index estimation, and hardens auth-tag comparison.
voip/sip/protocol.py Stores initialization task, guards early INVITEs, improves RTP address selection, removes error_received.
voip/rtp.py Updates docstring to match WARNING-level logging on SRTP auth failure.
voip/audio.py Allows WhisperModel instance injection for shared model reuse across calls.
tests/test_rtp.py Updates SRTP invalid-auth test description to match warning log behavior.
tests/sip/test_protocol.py Removes tests for error_received after method removal.
README.md Removes a claim about unencrypted SIP/RTP not being supported.

You can also share your feedback on Copilot code review. Take the survey.

# early INVITE must wait for the mux. Skip if already available.
if self._rtp_protocol is None:
if self._initialize_task is not None:
await self._initialize_task
Comment on lines +586 to +590
if remote_audio is not None and remote_audio.port != 0:
media_conn = remote_audio.connection
session_conn = request.body.connection if request.body else None
conn = media_conn or session_conn
if conn is not None:
Comment on lines +134 to +138
def _estimate_recv_index(self, seq: int) -> tuple[int, int]:
"""Estimate the packet index and new ROC for a received sequence number.

Implements the index estimation algorithm from RFC 3711 §3.3.1.

Comment on lines 21 to +24
All signalling uses **SIP over TLS** (SIPS, RFC 3261 §26) and all media is
protected with **SRTP** ([RFC 3711](https://tools.ietf.org/html/rfc3711))
using the `AES_CM_128_HMAC_SHA1_80` cipher suite with SDES key exchange
([RFC 4568](https://tools.ietf.org/html/rfc4568)). Unencrypted SIP or RTP
is not supported.
([RFC 4568](https://tools.ietf.org/html/rfc4568)).
Comment on lines 170 to 174
try:
asyncio.get_running_loop().create_task(self._initialize())
self._initialize_task = asyncio.get_running_loop().create_task(
self._initialize()
)
except RuntimeError:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants