fix real cell RTP bridge readiness

This commit is contained in:
2026-09-17 14:29:37 +08:00
parent b6d0af1a56
commit 668c12e523
10 changed files with 781 additions and 51 deletions
+164 -2
View File
@@ -6,7 +6,7 @@ import tempfile
import unittest
from pathlib import Path
from types import SimpleNamespace
from typing import cast
from typing import Any, cast
from agent_call.real_cell import (
CellCallConfig,
@@ -75,11 +75,173 @@ class RealCellTests(unittest.TestCase):
self.assertEqual(RTPMedia._payload(packet), payload)
self.assertIsNone(RTPMedia._payload(b"bad"))
def test_cell_config_rejects_non_pcma_and_bad_port(self) -> None:
def test_nonblocking_receive_returns_no_packet(self) -> None:
media = RTPMedia("127.0.0.1", 0)
try:
self.assertIsNone(media.receive(0.0))
finally:
media.close()
def test_rtp_receive_filters_payload_peer_and_ssrc(self) -> None:
media = RTPMedia("127.0.0.1", 0)
sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sender.bind(("127.0.0.1", 0))
media.peer = ("127.0.0.1", sender.getsockname()[1])
def packet(payload_type: int, ssrc: int, payload: bytes) -> bytes:
return struct.pack("!BBHII", 0x80, payload_type, 1, 0, ssrc) + payload
try:
sender.sendto(packet(0, 1, b"wrong-pt"), media.address)
self.assertIsNone(media.receive(0.2))
sender.sendto(packet(8, 1, b"voice"), media.address)
self.assertEqual(media.receive(0.2), b"voice")
sender.sendto(packet(8, 2, b"wrong-ssrc"), media.address)
self.assertIsNone(media.receive(0.2))
finally:
sender.close()
media.close()
def test_external_media_peer_comes_from_ari(self) -> None:
config = CellCallConfig("http://127.0.0.1:8088", "u", "p")
call = cast(
Any,
RealCellCall(
config,
cast(Any, SimpleNamespace(config={})),
cast(Any, SimpleNamespace()),
),
)
media = RTPMedia("127.0.0.1", 0)
calls: list[tuple[str, str, dict | None]] = []
class FakeARI:
def request(self, method: str, resource: str, params=None, **_kwargs):
calls.append((method, resource, params))
if params and params.get("variable") == "UNICASTRTP_LOCAL_ADDRESS":
return {"value": "127.0.0.1"}
return {"value": "12345"}
call.media = media
call.ari = FakeARI()
try:
call._set_external_media_peer("external-1")
self.assertEqual(media.peer, ("127.0.0.1", 12345))
self.assertEqual(len(calls), 2)
finally:
media.close()
def test_add_when_ready_marks_only_after_success(self) -> None:
config = CellCallConfig("http://127.0.0.1:8088", "u", "p")
call = cast(
Any,
RealCellCall(
config,
cast(Any, SimpleNamespace(config={})),
cast(Any, SimpleNamespace()),
),
)
class FakeARI:
def __init__(self) -> None:
self.attempts = 0
def request(self, method: str, _resource: str, _params=None, **_kwargs):
if method == "POST":
self.attempts += 1
if self.attempts == 1:
raise CellCallError("ARI_HTTP_422", "not in Stasis", True)
return {}
fake_ari = FakeARI()
call.ari = fake_ari
self.assertTrue(call._add_when_ready("target"))
self.assertEqual(fake_ari.attempts, 2)
self.assertIn("target", call._known_channels)
def test_wait_answer_requires_bridge_membership(self) -> None:
config = CellCallConfig("http://127.0.0.1:8088", "u", "p", event_timeout_s=1.0)
call = cast(
Any,
RealCellCall(
config,
cast(Any, SimpleNamespace(config={})),
cast(Any, SimpleNamespace()),
),
)
call.target_channel_id = "target"
call.external_channel_id = "external"
call.media = RTPMedia("127.0.0.1", 0)
call.media.peer = ("127.0.0.1", 12345)
bridge_members = [{"external"}, {"external", "target"}]
class FakeARI:
def request(self, method: str, resource: str, _params=None, **_kwargs):
if method == "GET" and resource == f"bridges/{call.bridge_id}":
return {"channels": list(bridge_members.pop(0))}
return {}
call.ari = FakeARI()
call.events.put(
{"type": "ChannelStateChange", "channel": {"id": "target", "state": "Up"}}
)
call.events.put({"type": "StasisStart", "channel": {"id": "target"}})
try:
call._wait_answer(SimpleNamespace())
self.assertEqual(bridge_members, [])
finally:
call.media.close()
def test_finish_recording_stops_then_reads_stored_file(self) -> None:
class FakeARI:
def __init__(self) -> None:
self.calls: list[tuple[str, str]] = []
def request(self, method: str, resource: str, **_kwargs):
self.calls.append((method, resource))
return {} if method == "POST" else b"RIFFtest"
with tempfile.TemporaryDirectory() as directory:
config = CellCallConfig(
"http://127.0.0.1:8088", "u", "p", recording_dir=directory
)
call = cast(
Any,
RealCellCall(
config,
cast(Any, SimpleNamespace(config={})),
cast(Any, SimpleNamespace()),
),
)
fake_ari = FakeARI()
call.ari = fake_ari
path = call._finish_recording()
self.assertIsNotNone(path)
self.assertEqual(fake_ari.calls[0][0], "POST")
self.assertIn("/stop", fake_ari.calls[0][1])
self.assertNotIn(
("DELETE", fake_ari.calls[0][1].rsplit("/stop", 1)[0]), fake_ari.calls
)
def test_cell_config_rejects_non_pcma_bad_port_and_prefix(self) -> None:
with self.assertRaises(CellCallError):
CellCallConfig("http://127.0.0.1:8088", "u", "p", rtp_format="ulaw")
with self.assertRaises(CellCallError):
CellCallConfig("http://127.0.0.1:8088", "u", "p", rtp_bind_port=65536)
with self.assertRaises(CellCallError):
CellCallConfig("http://127.0.0.1:8088", "u", "p", dial_prefix="7089+")
self.assertEqual(
CellCallConfig(
"http://127.0.0.1:8088", "u", "p", dial_prefix=""
).dial_prefix,
"",
)
self.assertEqual(
CellCallConfig(
"http://127.0.0.1:8088", "u", "p", dial_prefix="mka755"
).dial_prefix,
"mka755",
)
def test_ledger_marks_in_progress_as_in_doubt(self) -> None:
with tempfile.TemporaryDirectory() as directory: