def test_rtp_rtx(self): receiver = RTCRtpReceiver('video', self.local_transport) self.assertEqual(receiver.transport, self.local_transport) receiver._track = RemoteStreamTrack(kind='video') run( receiver.receive( RTCRtpReceiveParameters( codecs=[ VP8_CODEC, RTCRtpCodecParameters(mimeType='video/rtx', clockRate=90000, payloadType=101, parameters={'apt': 100}), ], encodings=[ RTCRtpEncodingParameters( ssrc=1234, payloadType=100, rtx=RTCRtpRtxParameters(ssrc=2345)) ]))) # receive RTX with payload packet = RtpPacket(payload_type=101, ssrc=2345, payload=b'\x00\x00') run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # receive RTX without payload packet = RtpPacket(payload_type=101, ssrc=2345) run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # shutdown run(receiver.stop())
async def test_rtp_rtx(self): async with create_receiver("video") as receiver: receiver._track = RemoteStreamTrack(kind="video") await receiver.receive( RTCRtpReceiveParameters( codecs=[ VP8_CODEC, RTCRtpCodecParameters( mimeType="video/rtx", clockRate=90000, payloadType=101, parameters={"apt": 100}, ), ], encodings=[ RTCRtpEncodingParameters( ssrc=1234, payloadType=100, rtx=RTCRtpRtxParameters(ssrc=2345), ) ], ) ) # receive RTX with payload packet = RtpPacket(payload_type=101, ssrc=2345, payload=b"\x00\x00") await receiver._handle_rtp_packet(packet, arrival_time_ms=0) # receive RTX without payload packet = RtpPacket(payload_type=101, ssrc=2345) await receiver._handle_rtp_packet(packet, arrival_time_ms=0)
def test_remove_video_frame(self): """ Video jitter buffer. """ jbuffer = JitterBuffer(capacity=128) packet = RtpPacket(sequence_number=0, timestamp=1234) packet._data = b"0000" frame = jbuffer.add(packet) self.assertIsNone(frame) packet = RtpPacket(sequence_number=1, timestamp=1234) packet._data = b"0001" frame = jbuffer.add(packet) self.assertIsNone(frame) packet = RtpPacket(sequence_number=2, timestamp=1234) packet._data = b"0002" frame = jbuffer.add(packet) self.assertIsNone(frame) packet = RtpPacket(sequence_number=3, timestamp=1235) packet._data = b"0003" frame = jbuffer.add(packet) self.assertIsNotNone(frame) self.assertEqual(frame.data, b"000000010002") self.assertEqual(frame.timestamp, 1234)
def test_add_ordered(self): jbuffer = JitterBuffer(capacity=4) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=0, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [0, None, None, None]) self.assertEqual(jbuffer._origin, 0) self.assertFalse(pli_flag) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=1, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [0, 1, None, None]) self.assertEqual(jbuffer._origin, 0) self.assertFalse(pli_flag) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=2, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [0, 1, 2, None]) self.assertEqual(jbuffer._origin, 0) self.assertFalse(pli_flag) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=3, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [0, 1, 2, 3]) self.assertEqual(jbuffer._origin, 0) self.assertFalse(pli_flag)
def test_add_seq_too_high_reset(self): jbuffer = JitterBuffer(capacity=4) jbuffer.add(RtpPacket(sequence_number=0, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) self.assertPackets(jbuffer, [0, None, None, None]) jbuffer.add(RtpPacket(sequence_number=3000, timestamp=1234)) self.assertEqual(jbuffer._origin, 3000) self.assertPackets(jbuffer, [3000, None, None, None])
def test_add_seq_too_low_reset(self): jbuffer = JitterBuffer(capacity=4) frame = jbuffer.add(RtpPacket(sequence_number=2000, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [2000, None, None, None]) self.assertEqual(jbuffer._origin, 2000) frame = jbuffer.add(RtpPacket(sequence_number=1, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [None, 1, None, None]) self.assertEqual(jbuffer._origin, 1)
def test_smart_remove(self): jbuffer = JitterBuffer(capacity=4) jbuffer.add(RtpPacket(sequence_number=0, timestamp=1234)) jbuffer.add(RtpPacket(sequence_number=1, timestamp=1234)) jbuffer.add(RtpPacket(sequence_number=3, timestamp=1235)) self.assertEqual(jbuffer._origin, 0) self.assertPackets(jbuffer, [0, 1, None, 3]) # remove 1 packet jbuffer.smart_remove(1) self.assertEqual(jbuffer._origin, 3) self.assertPackets(jbuffer, [None, None, None, 3])
def test_get_header_extensions(self): packet = RtpPacket() # none self.assertEqual(get_header_extensions(packet), []) # one-byte, single value packet.extension_profile = 0xBEDE packet.extension_value = b'\x900\x00\x00' self.assertEqual(get_header_extensions(packet), [ (9, b'0'), ]) # one-byte, two values packet.extension_profile = 0xBEDE packet.extension_value = b'\x10\xc18sdparta_0' self.assertEqual(get_header_extensions(packet), [ (1, b'\xc1'), (3, b'sdparta_0'), ]) # two-byte, single value packet.extension_profile = 0x1000 packet.extension_value = b'\xff\x010\x00' self.assertEqual(get_header_extensions(packet), [ (255, b'0'), ])
def test_add_seq_too_low_drop(self): jbuffer = JitterBuffer(capacity=4) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=2, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [None, None, 2, None]) self.assertEqual(jbuffer._origin, 2) self.assertFalse(pli_flag) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=1, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [None, None, 2, None]) self.assertEqual(jbuffer._origin, 2) self.assertFalse(pli_flag)
def test_add_seq_too_high_discard_four(self): jbuffer = JitterBuffer(capacity=4) jbuffer.add(RtpPacket(sequence_number=0, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=1, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=3, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=7, timestamp=1235)) self.assertEqual(jbuffer._origin, 7) self.assertPackets(jbuffer, [None, None, None, 7])
def test_add_seq_too_high_discard_one_v2(self): jbuffer = JitterBuffer(capacity=4) jbuffer.add(RtpPacket(sequence_number=0, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=2, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=3, timestamp=1235)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=4, timestamp=1235)) self.assertEqual(jbuffer._origin, 3) self.assertPackets(jbuffer, [4, None, None, 3])
def test_rtp_rtx_unknown_ssrc(self): receiver = RTCRtpReceiver("video", self.local_transport) self.assertEqual(receiver.transport, self.local_transport) receiver._track = RemoteStreamTrack(kind="video") run( receiver.receive( RTCRtpReceiveParameters( codecs=[ VP8_CODEC, RTCRtpCodecParameters( mimeType="video/rtx", clockRate=90000, payloadType=101, parameters={"apt": 100}, ), ] ) ) ) # receive RTX with unknown SSRC packet = RtpPacket(payload_type=101, ssrc=1234) run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # shutdown run(receiver.stop())
def test_set_header_extensions(self): packet = RtpPacket() # none set_header_extensions(packet, {}) self.assertEqual(packet.extension_profile, 0) self.assertEqual(packet.extension_value, None) # one-byte, single value set_header_extensions(packet, [ (9, b'0'), ]) self.assertEqual(packet.extension_profile, 0xBEDE) self.assertEqual(packet.extension_value, b'\x900\x00\x00') # one-byte, two values set_header_extensions(packet, [ (1, b'\xc1'), (3, b'sdparta_0'), ]) self.assertEqual(packet.extension_profile, 0xBEDE) self.assertEqual(packet.extension_value, b'\x10\xc18sdparta_0') # two-byte, single value set_header_extensions(packet, [ (255, b'0'), ]) self.assertEqual(packet.extension_profile, 0x1000) self.assertEqual(packet.extension_value, b'\xff\x010\x00')
def create_packets(self, count, seq=0): packets = [] for i in range(count): packets.append( RtpPacket(payload_type=0, sequence_number=(seq + i) % RTP_SEQ_MODULO, timestamp=i * 160)) return packets
def test_add_unordered(self): jbuffer = JitterBuffer(capacity=4) frame = jbuffer.add(RtpPacket(sequence_number=1, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [None, 1, None, None]) self.assertEqual(jbuffer._origin, 1) frame = jbuffer.add(RtpPacket(sequence_number=3, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [None, 1, None, 3]) self.assertEqual(jbuffer._origin, 1) frame = jbuffer.add(RtpPacket(sequence_number=2, timestamp=1234)) self.assertIsNone(frame) self.assertPackets(jbuffer, [None, 1, 2, 3]) self.assertEqual(jbuffer._origin, 1)
async def test_rtp_unknown_payload_type(self): async with create_receiver("video") as receiver: receiver._track = RemoteStreamTrack(kind="video") await receiver.receive(RTCRtpReceiveParameters(codecs=[VP8_CODEC])) # receive RTP with unknown payload type packet = RtpPacket(payload_type=123) await receiver._handle_rtp_packet(packet, arrival_time_ms=0)
def create_rtp_packets(count, seq=0): packets = [] for i in range(count): packets.append(RtpPacket( payload_type=0, sequence_number=uint16_add(seq, i), ssrc=1234, timestamp=i * 160)) return packets
def test_add_seq_too_high_discard_more(self): jbuffer = JitterBuffer(capacity=4) jbuffer.add(RtpPacket(sequence_number=0, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=1, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=2, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=3, timestamp=1234)) self.assertEqual(jbuffer._origin, 0) jbuffer.add(RtpPacket(sequence_number=8, timestamp=1234)) self.assertEqual(jbuffer._origin, 8) self.assertPackets(jbuffer, [8, None, None, None])
def test_route_rtp_ambiguous_payload_type(self): receiver1 = object() receiver2 = object() router = RtpRouter() router.register_receiver(receiver1, ssrcs=[1234, 2345], payload_types=[96, 97]) router.register_receiver(receiver2, ssrcs=[3456, 4567], payload_types=[96, 97]) # known SSRC and payload type self.assertEqual( router.route_rtp(RtpPacket(ssrc=1234, payload_type=96)), receiver1 ) self.assertEqual( router.route_rtp(RtpPacket(ssrc=2345, payload_type=97)), receiver1 ) self.assertEqual( router.route_rtp(RtpPacket(ssrc=3456, payload_type=96)), receiver2 ) self.assertEqual( router.route_rtp(RtpPacket(ssrc=4567, payload_type=97)), receiver2 ) # unknown SSRC, ambiguous payload type self.assertEqual(router.route_rtp(RtpPacket(ssrc=5678, payload_type=96)), None) self.assertEqual(router.route_rtp(RtpPacket(ssrc=5678, payload_type=97)), None)
def test_route_rtp(self): receiver1 = object() receiver2 = object() router = RtpRouter() router.register_receiver(receiver1, ssrcs=[1234, 2345], payload_types=[96, 97]) router.register_receiver(receiver2, ssrcs=[3456, 4567], payload_types=[98, 99]) # known SSRC and payload type self.assertEqual( router.route_rtp(RtpPacket(ssrc=1234, payload_type=96)), receiver1 ) self.assertEqual( router.route_rtp(RtpPacket(ssrc=2345, payload_type=97)), receiver1 ) self.assertEqual( router.route_rtp(RtpPacket(ssrc=3456, payload_type=98)), receiver2 ) self.assertEqual( router.route_rtp(RtpPacket(ssrc=4567, payload_type=99)), receiver2 ) # unknown SSRC, known payload type self.assertEqual( router.route_rtp(RtpPacket(ssrc=5678, payload_type=96)), receiver1 ) self.assertEqual(router.ssrc_table[5678], receiver1) # unknown SSRC and payload type self.assertEqual(router.route_rtp(RtpPacket(ssrc=6789, payload_type=100)), None)
def test_rtp_unknown_payload_type(self): receiver = RTCRtpReceiver('video', self.local_transport) self.assertEqual(receiver.transport, self.local_transport) receiver._track = RemoteStreamTrack(kind='video') run(receiver.receive(RTCRtpReceiveParameters(codecs=[VP8_CODEC]))) # receive RTP with unknown payload type packet = RtpPacket(payload_type=123) run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # shutdown run(receiver.stop())
def test_rtp_empty_video_packet(self): receiver = RTCRtpReceiver("video", self.local_transport) self.assertEqual(receiver.transport, self.local_transport) receiver._track = RemoteStreamTrack(kind="video") run(receiver.receive(RTCRtpReceiveParameters(codecs=[VP8_CODEC]))) # receive RTP with empty payload packet = RtpPacket(payload_type=100) run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # shutdown run(receiver.stop())
def test_pli_flag(self): """ Video jitter buffer. """ jbuffer = JitterBuffer(capacity=128, is_video=True) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=2000, timestamp=1234)) self.assertIsNone(frame) self.assertEqual(jbuffer._origin, 2000) self.assertFalse(pli_flag) # test_add_seq_too_low_reset for video (capacity >= 128) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=1, timestamp=1234)) self.assertIsNone(frame) self.assertEqual(jbuffer._origin, 1) self.assertTrue(pli_flag) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=128, timestamp=1235)) self.assertIsNone(frame) self.assertEqual(jbuffer._origin, 1) self.assertFalse(pli_flag) # test_add_seq_too_high_discard_one for video (capacity >= 128) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=129, timestamp=1235)) self.assertIsNone(frame) self.assertEqual(jbuffer._origin, 128) self.assertTrue(pli_flag) # test_add_seq_too_high_reset for video (capacity >= 128) pli_flag, frame = jbuffer.add( RtpPacket(sequence_number=2000, timestamp=2345)) self.assertIsNone(frame) self.assertEqual(jbuffer._origin, 2000) self.assertTrue(pli_flag)
def test_remove_frame(self): jbuffer = JitterBuffer(capacity=4) packet = RtpPacket(sequence_number=0, timestamp=1234) packet._data = b'0000' frame = jbuffer.add(packet) self.assertIsNone(frame) packet = RtpPacket(sequence_number=1, timestamp=1234) packet._data = b'0001' frame = jbuffer.add(packet) self.assertIsNone(frame) packet = RtpPacket(sequence_number=2, timestamp=1234) packet._data = b'0002' frame = jbuffer.add(packet) self.assertIsNone(frame) packet = RtpPacket(sequence_number=3, timestamp=1235) packet._data = b'0003' frame = jbuffer.add(packet) self.assertIsNotNone(frame) self.assertEqual(frame.data, b'000000010002') self.assertEqual(frame.timestamp, 1234)
def test_rtp_empty_video_packet(self): receiver = RTCRtpReceiver('video', self.local_transport) self.assertEqual(receiver.transport, self.local_transport) receiver._track = RemoteStreamTrack(kind='video') run(receiver.receive(RTCRtpParameters(codecs=[ RTCRtpCodecParameters(name='VP8', clockRate=90000, payloadType=100), ]))) # receive RTP with empty payload packet = RtpPacket(payload_type=100) run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # shutdown run(receiver.stop())
def create_rtp_video_packets(self, codec, frames, seq=0): encoder = get_encoder(codec) packets = [] for frame in self.create_video_frames(width=640, height=480, count=frames): payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 1) packet = RtpPacket(payload_type=codec.payloadType, sequence_number=seq, ssrc=1234, timestamp=timestamp) packet.payload = payloads[0] packet.marker = 1 packets.append(packet) seq = uint16_add(seq, 1) return packets
def test_rtp_empty_video_packet(self): transport, remote = dummy_dtls_transport_pair() receiver = RTCRtpReceiver('video', transport) self.assertEqual(receiver.transport, transport) receiver._track = RemoteStreamTrack(kind='audio') run( receiver.receive( RTCRtpParameters(codecs=[ RTCRtpCodecParameters( name='VP8', clockRate=90000, payloadType=100), ]))) # receive RTP with empty payload packet = RtpPacket(payload_type=100) run(receiver._handle_rtp_packet(packet))
def test_rtp_rtx_unknown_ssrc(self): receiver = RTCRtpReceiver('video', self.local_transport) self.assertEqual(receiver.transport, self.local_transport) receiver._track = RemoteStreamTrack(kind='video') run(receiver.receive(RTCRtpReceiveParameters( codecs=[ RTCRtpCodecParameters(name='VP8', clockRate=90000, payloadType=100), RTCRtpCodecParameters(name='rtx', clockRate=90000, payloadType=101, parameters={'apt': 100}), ]))) # receive RTX with unknown SSRC packet = RtpPacket(payload_type=101, ssrc=1234) run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # shutdown run(receiver.stop())
async def test_rtp_rtx_unknown_ssrc(self): async with create_receiver("video") as receiver: receiver._track = RemoteStreamTrack(kind="video") await receiver.receive( RTCRtpReceiveParameters( codecs=[ VP8_CODEC, RTCRtpCodecParameters( mimeType="video/rtx", clockRate=90000, payloadType=101, parameters={"apt": 100}, ), ] ) ) # receive RTX with unknown SSRC packet = RtpPacket(payload_type=101, ssrc=1234) await receiver._handle_rtp_packet(packet, arrival_time_ms=0)
def roundtrip(self, width, height): """ Round-trip a VideoFrame through encoder then decoder. """ encoder = get_encoder(H264_CODEC) decoder = get_decoder(H264_CODEC) # encode frame = VideoFrame(width=width, height=height) packages = encoder.encode(frame) # depacketize data = b'' for package in packages: packet = RtpPacket(payload=package) decoder.parse(packet) data += packet._data # decode frames = decoder.decode(data) self.assertEqual(len(frames), 1) self.assertEqual(frames[0].width, width) self.assertEqual(frames[0].height, height)