carrot/teleoprtc_repo/tests/test_integration.py
Vehicle Researcher d64fb1838d openpilot v0.9.7 release
date: 2024-06-11T01:36:39
master commit: f8cb04e4a8b032b72a909f68b808a50936184bee
2024-06-11 16:32:27 -07:00

138 lines
4.2 KiB
Python
Executable File

#!/usr/bin/env python3
import asyncio
import sys
import unittest
from aiortc.mediastreams import AudioStreamTrack, VideoStreamTrack
from parameterized import parameterized
from teleoprtc.builder import WebRTCOfferBuilder, WebRTCAnswerBuilder
from teleoprtc.stream import StreamingOffer
from teleoprtc.info import parse_info_from_offer
if sys.version_info >= (3, 11):
timeout = asyncio.timeout
else:
class Timeout:
def __init__(self, delay: float):
self._delay = delay
self._task = None
self._timeout_handle = None
def _timeout(self):
if self._task:
self._task.cancel()
async def __aenter__(self):
self._task = asyncio.current_task()
loop = asyncio.events.get_running_loop()
self._timeout_handle = loop.call_later(self._delay, self._timeout)
return self
async def __aexit__(self, exc_type, exc, tb):
if self._timeout_handle:
self._timeout_handle.cancel()
if exc_type is asyncio.CancelledError and self._task and self._task.cancelled():
raise asyncio.TimeoutError from exc
return False
def timeout(delay):
return Timeout(delay)
class SimpleAnswerProvider:
def __init__(self):
self.stream = None
async def __call__(self, offer: StreamingOffer):
assert self.stream is None, "This may only be called once"
info = parse_info_from_offer(offer.sdp)
builder = WebRTCAnswerBuilder(offer.sdp)
for cam in offer.video:
builder.add_video_stream(cam, VideoStreamTrack())
if info.expected_audio_track:
builder.add_audio_stream(AudioStreamTrack())
if info.incoming_audio_track:
builder.offer_to_receive_audio_stream()
self.stream = builder.stream()
answer = await self.stream.start()
return answer
class TestStreamIntegration(unittest.IsolatedAsyncioTestCase):
@parameterized.expand([
# name, recv_cameras, recv_audio, messaging
("multi_camera", ["driver", "wideRoad", "road"], False, False),
("camera_and_audio", ["driver"], True, False),
("camera_and__messaging", ["driver"], False, True),
("camera_and_audio_and_messaging", ["driver", "wideRoad", "road"], True, True),
])
async def test_multi_camera(self, name, cameras, recv_audio, add_messaging):
simple_answerer = SimpleAnswerProvider()
offer_builder = WebRTCOfferBuilder(simple_answerer)
for cam in cameras:
offer_builder.offer_to_receive_video_stream(cam)
if recv_audio:
offer_builder.offer_to_receive_audio_stream()
if add_messaging:
offer_builder.add_messaging()
stream = offer_builder.stream()
_ = await stream.start()
self.assertTrue(stream.is_started)
try:
async with timeout(2):
await stream.wait_for_connection()
except TimeoutError:
self.fail("Timed out waiting for connection")
self.assertTrue(stream.is_connected_and_ready)
self.assertEqual(stream.has_messaging_channel(), add_messaging)
if stream.has_messaging_channel():
channel = stream.get_messaging_channel()
self.assertIsNotNone(channel)
self.assertEqual(channel.readyState, "open")
self.assertEqual(stream.has_incoming_audio_track(), recv_audio)
if stream.has_incoming_audio_track():
track = stream.get_incoming_audio_track(False)
self.assertIsNotNone(track)
self.assertEqual(track.readyState, "live")
self.assertEqual(track.kind, "audio")
# test audio recv
try:
async with timeout(1):
await track.recv()
except TimeoutError:
self.fail("Timed out waiting for audio frame")
for cam in cameras:
self.assertTrue(stream.has_incoming_video_track(cam))
if stream.has_incoming_video_track(cam):
track = stream.get_incoming_video_track(cam, False)
self.assertIsNotNone(track)
self.assertEqual(track.readyState, "live")
self.assertEqual(track.kind, "video")
# test video recv
try:
async with timeout(1):
await stream.get_incoming_video_track(cam, False).recv()
except TimeoutError:
self.fail("Timed out waiting for video frame")
await stream.stop()
await simple_answerer.stream.stop()
self.assertFalse(stream.is_started)
self.assertFalse(stream.is_connected_and_ready)
if __name__ == '__main__':
unittest.main()