def test_srtp_unprotect_error(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyRtpReceiver() session1._register_rtp_receiver( receiver1, RTCRtpParameters(rtcp=RTCRtcpParameters(ssrc=1831097322))) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) receiver2 = DummyRtpReceiver() session2._register_rtp_receiver( receiver2, RTCRtpParameters(rtcp=RTCRtcpParameters(ssrc=4028317929))) run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) # send same RTP twice, to trigger error on the receiver side: # "replay check failed (bad index)" run(session1._send_rtp(RTP)) run(session1._send_rtp(RTP)) run(asyncio.sleep(0.5)) self.assertEqual(len(receiver2.rtcp_packets), 0) self.assertEqual(len(receiver2.rtp_packets), 1) # shutdown run(session1.stop()) run(session2.stop())
def test_rtp(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyRtpReceiver() session1._register_rtp_receiver( receiver1, RTCRtpParameters(rtcp=RTCRtcpParameters(ssrc=1831097322))) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) receiver2 = DummyRtpReceiver() session2._register_rtp_receiver( receiver2, RTCRtpParameters(rtcp=RTCRtcpParameters(ssrc=4028317929))) run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) self.assertCounters(session1, session2, 2, 2) # send RTP run(session1._send_rtp(RTP)) run(asyncio.sleep(0.1)) self.assertCounters(session1, session2, 3, 2) self.assertEqual(len(receiver2.rtcp_packets), 0) self.assertEqual(len(receiver2.rtp_packets), 1) # send RTCP run(session2._send_rtp(RTCP)) run(asyncio.sleep(0.1)) self.assertCounters(session1, session2, 3, 3) self.assertEqual(len(receiver1.rtcp_packets), 1) self.assertEqual(len(receiver1.rtp_packets), 0) # shutdown run(session1.stop()) run(asyncio.sleep(0.5)) self.assertCounters(session1, session2, 4, 3) self.assertEqual(session1.state, 'closed') self.assertEqual(session2.state, 'closed') # try closing again run(session1.stop()) run(session2.stop()) # try sending after close with self.assertRaises(ConnectionError): run(session1._send_rtp(RTP))
async def test_handle_rtcp_rr(self): async with dummy_dtls_transport_pair() as (local_transport, _): sender = RTCRtpSender(VideoStreamTrack(), local_transport) self.assertEqual(sender.kind, "video") await sender.send(RTCRtpParameters(codecs=[VP8_CODEC])) # receive RTCP RR packet = RtcpRrPacket( ssrc=1234, reports=[ RtcpReceiverInfo( ssrc=sender._ssrc, fraction_lost=0, packets_lost=0, highest_sequence=630, jitter=1906, lsr=0, dlsr=0, ) ], ) await sender._handle_rtcp_packet(packet) # check stats report = await sender.getStats() self.assertTrue(isinstance(report, RTCStatsReport)) self.assertEqual( sorted([s.type for s in report.values()]), ["outbound-rtp", "remote-inbound-rtp", "transport"], ) # clean shutdown await sender.stop()
async def test_handle_rtcp_remb(self): async with dummy_dtls_transport_pair() as (local_transport, _): sender = RTCRtpSender(VideoStreamTrack(), local_transport) self.assertEqual(sender.kind, "video") await sender.send(RTCRtpParameters(codecs=[VP8_CODEC])) # receive RTCP feedback REMB packet = RtcpPsfbPacket( fmt=RTCP_PSFB_APP, ssrc=1234, media_ssrc=0, fci=pack_remb_fci(4160000, [sender._ssrc]), ) await sender._handle_rtcp_packet(packet) # receive RTCP feedback REMB (malformed) packet = RtcpPsfbPacket(fmt=RTCP_PSFB_APP, ssrc=1234, media_ssrc=0, fci=b"JUNK") await sender._handle_rtcp_packet(packet) # clean shutdown await sender.stop()
def test_rtp_and_rtcp(self): transport, remote = dummy_dtls_transport_pair() receiver = RTCRtpReceiver('audio', transport) self.assertEqual(receiver.transport, transport) receiver._track = RemoteStreamTrack(kind='audio') run(receiver.receive(RTCRtpParameters(codecs=[PCMU_CODEC]))) # receive RTP run(remote.send(load('rtp.bin'))) # receive RTCP run(remote.send(load('rtcp_sr.bin'))) # receive truncated RTCP run(remote.send(b'\x81\xca\x00')) # receive garbage run(remote.send(b'garbage')) # check remote track frame = run(receiver._track.recv()) self.assertTrue(isinstance(frame, AudioFrame)) # shutdown run(asyncio.sleep(0.1)) receiver.stop() run(asyncio.sleep(0))
def test_rtp_and_rtcp(self): transport, remote = dummy_dtls_transport_pair() receiver = RTCRtpReceiver('audio', transport) self.assertEqual(receiver.transport, transport) receiver._track = RemoteStreamTrack(kind='audio') run(receiver.receive(RTCRtpParameters(codecs=[PCMU_CODEC]))) # receive RTP packet = RtpPacket.parse(load('rtp.bin')) run(receiver._handle_rtp_packet(packet)) # receive RTCP for packet in RtcpPacket.parse(load('rtcp_sr.bin')): run(receiver._handle_rtcp_packet(packet)) self.assertEqual(sorted(receiver._stats.keys()), ['remote-inbound-rtp', 'remote-outbound-rtp']) # check remote track frame = run(receiver._track.recv()) self.assertTrue(isinstance(frame, AudioFrame)) # shutdown run(receiver.stop()) run(asyncio.sleep(0))
async def test_send_keyframe(self): """ Ask for a keyframe. """ queue = asyncio.Queue() async def mock_send_rtp(data): if not is_rtcp(data): await queue.put(RtpPacket.parse(data)) async with dummy_dtls_transport_pair() as (local_transport, _): local_transport._send_rtp = mock_send_rtp sender = RTCRtpSender(VideoStreamTrack(), local_transport) self.assertEqual(sender.kind, "video") await sender.send(RTCRtpParameters(codecs=[VP8_CODEC])) # wait for one packet to be transmitted, and ask for keyframe await queue.get() sender._send_keyframe() # wait for packet to be transmitted, then shutdown await asyncio.sleep(0.1) await sender.stop()
def test_handle_rtcp_rr(self): transport, remote = dummy_dtls_transport_pair() sender = RTCRtpSender(VideoStreamTrack(), transport) self.assertEqual(sender.kind, 'video') self.assertEqual(sender.transport, transport) run( sender.send( RTCRtpParameters(codecs=[ RTCRtpCodecParameters( name='VP8', clockRate=90000, payloadType=100), ]))) # receive RTCP RR for packet in RtcpPacket.parse(load('rtcp_rr.bin')): run(sender._handle_rtcp_packet(packet)) # check stats report = run(sender.getStats()) self.assertTrue(isinstance(report, RTCStatsReport)) self.assertEqual(sorted([s.type for s in report.values()]), ['outbound-rtp', 'remote-inbound-rtp', 'transport']) # clean shutdown run(sender.stop())
def test_rtp_and_rtcp(self): transport, remote = dummy_dtls_transport_pair() receiver = RTCRtpReceiver('audio', transport) self.assertEqual(receiver.transport, transport) receiver._track = RemoteStreamTrack(kind='audio') self.assertEqual(receiver._track.readyState, 'live') run(receiver.receive(RTCRtpParameters(codecs=[PCMU_CODEC]))) # receive RTP packet = RtpPacket.parse(load('rtp.bin')) run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # receive RTCP SR for packet in RtcpPacket.parse(load('rtcp_sr.bin')): run(receiver._handle_rtcp_packet(packet)) # check stats report = run(receiver.getStats()) self.assertTrue(isinstance(report, RTCStatsReport)) self.assertEqual(sorted(report.keys()), ['inbound-rtp', 'remote-outbound-rtp']) # check remote track frame = run(receiver._track.recv()) self.assertTrue(isinstance(frame, AudioFrame)) # shutdown run(receiver.stop()) self.assertEqual(receiver._track.readyState, 'ended')
def test_handle_rtcp_remb(self): sender = RTCRtpSender(VideoStreamTrack(), self.local_transport) self.assertEqual(sender.kind, 'video') run( sender.send( RTCRtpParameters(codecs=[ RTCRtpCodecParameters( name='VP8', clockRate=90000, payloadType=100), ]))) # receive RTCP feedback REMB packet = RtcpPsfbPacket(fmt=RTCP_PSFB_APP, ssrc=1234, media_ssrc=0, fci=b'REMB\x01\x13\xf7\xa0\x96\xbe\x96\xcf') run(sender._handle_rtcp_packet(packet)) # receive RTCP feedback REMB (malformed) packet = RtcpPsfbPacket(fmt=RTCP_PSFB_APP, ssrc=1234, media_ssrc=0, fci=b'JUNK') run(sender._handle_rtcp_packet(packet)) # clean shutdown run(sender.stop())
def test_retransmit(self): """ Ask for an RTP packet retransmission. """ transport = FakeDtlsTransport() sender = RTCRtpSender(VideoStreamTrack(), transport) self.assertEqual(sender.kind, 'video') self.assertEqual(sender.transport, transport) run( sender.send( RTCRtpParameters(codecs=[ RTCRtpCodecParameters( name='VP8', clockRate=90000, payloadType=100), ]))) # wait for one packet to be transmitted, and ask to retransmit packet = run(transport.queue.get()) run(sender._retransmit(packet.sequence_number)) # wait for packet to be retransmitted, then shutdown run(asyncio.sleep(0.5)) run(sender.stop()) # check packet was retransmitted found_rtx = False while not transport.queue.empty(): queue_packet = transport.queue.get_nowait() if queue_packet.sequence_number == packet.sequence_number: found_rtx = True self.assertTrue(found_rtx)
def test_send_keyframe(self): """ Ask for a keyframe. """ queue = asyncio.Queue() async def mock_send_rtp(data): if not is_rtcp(data): await queue.put(RtpPacket.parse(data)) self.local_transport._send_rtp = mock_send_rtp sender = RTCRtpSender(VideoStreamTrack(), self.local_transport) self.assertEqual(sender.kind, 'video') run( sender.send( RTCRtpParameters(codecs=[ RTCRtpCodecParameters( name='VP8', clockRate=90000, payloadType=100), ]))) # wait for one packet to be transmitted, and ask for keyframe run(queue.get()) sender._send_keyframe() # wait for packet to be transmitted, then shutdown run(asyncio.sleep(0.1)) run(sender.stop())
def test_padding_only_with_header_extensions(self): extensions_map = rtp.HeaderExtensionsMap() extensions_map.configure( RTCRtpParameters(headerExtensions=[ RTCRtpHeaderExtensionParameters( id=2, uri= "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time", ) ])) data = load("rtp_only_padding_with_header_extensions.bin") packet = RtpPacket.parse(data, extensions_map) self.assertEqual(packet.version, 2) self.assertEqual(packet.marker, 0) self.assertEqual(packet.payload_type, 98) self.assertEqual(packet.sequence_number, 22138) self.assertEqual(packet.timestamp, 3171065731) self.assertEqual(packet.csrc, []) self.assertEqual(packet.extensions, rtp.HeaderExtensions(abs_send_time=15846540)) self.assertEqual(len(packet.payload), 0) self.assertEqual(packet.padding_size, 224) serialized = packet.serialize(extensions_map) self.assertEqual(len(serialized), len(data)) self.assertEqual(serialized[0:20], data[0:20]) self.assertEqual(serialized[-1], data[-1])
def test_retransmit(self): """ Ask for an RTP packet retransmission. """ transport = FakeDtlsTransport() sender = RTCRtpSender(VideoStreamTrack(), transport) self.assertEqual(sender.kind, 'video') self.assertEqual(sender.transport, transport) run( sender.send( RTCRtpParameters(codecs=[ RTCRtpCodecParameters( name='VP8', clockRate=90000, payloadType=100), ]))) # wait for one packet to be transmitted, and ask to retransmit packet = run(transport.queue.get()) run(sender._retransmit(packet.sequence_number)) # wait for packet to be transmitted rtx_packet = run(transport.queue.get()) self.assertEqual(rtx_packet.sequence_number, packet.sequence_number) # clean shutdown run(sender.stop())
def test_rtx(self): extensions_map = rtp.HeaderExtensionsMap() extensions_map.configure( RTCRtpParameters(headerExtensions=[ RTCRtpHeaderExtensionParameters( id=9, uri="urn:ietf:params:rtp-hdrext:sdes:mid") ])) data = load("rtp_with_sdes_mid.bin") packet = RtpPacket.parse(data, extensions_map) # wrap / unwrap RTX rtx = wrap_rtx(packet, payload_type=112, sequence_number=12345, ssrc=1234) recovered = unwrap_rtx(rtx, payload_type=111, ssrc=4084547440) # check roundtrip self.assertEqual(recovered.version, packet.version) self.assertEqual(recovered.marker, packet.marker) self.assertEqual(recovered.payload_type, packet.payload_type) self.assertEqual(recovered.sequence_number, packet.sequence_number) self.assertEqual(recovered.timestamp, packet.timestamp) self.assertEqual(recovered.ssrc, packet.ssrc) self.assertEqual(recovered.csrc, packet.csrc) self.assertEqual(recovered.extensions, packet.extensions) self.assertEqual(recovered.payload, packet.payload)
def test_connection_error(self): """ Close the underlying transport before the receiver. """ transport, _ = dummy_dtls_transport_pair() receiver = RTCRtpReceiver('audio', transport) self.assertEqual(receiver.transport, transport) receiver._track = RemoteStreamTrack(kind='audio') receiver._ssrc = 1234 run(receiver.receive(RTCRtpParameters(codecs=[PCMU_CODEC]))) # receive a packet to prime RTCP packet = RtpPacket.parse(load('rtp.bin')) run(receiver._handle_rtp_packet(packet, arrival_time_ms=0)) # break connection run(transport.stop()) # give RTCP time to send a report run(asyncio.sleep(2)) # shutdown run(receiver.stop())
def test_track_ended(self): track = AudioStreamTrack() sender = RTCRtpSender(track, self.local_transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) track.stop() run(asyncio.sleep(0.5))
def test_handle_rtcp_rr(self): sender = RTCRtpSender(VideoStreamTrack(), self.local_transport) self.assertEqual(sender.kind, 'video') run(sender.send(RTCRtpParameters(codecs=[VP8_CODEC]))) # receive RTCP RR packet = RtcpRrPacket(ssrc=1234, reports=[ RtcpReceiverInfo(ssrc=sender._ssrc, fraction_lost=0, packets_lost=0, highest_sequence=630, jitter=1906, lsr=0, dlsr=0) ]) run(sender._handle_rtcp_packet(packet)) # check stats report = run(sender.getStats()) self.assertTrue(isinstance(report, RTCStatsReport)) self.assertEqual(sorted([s.type for s in report.values()]), ['outbound-rtp', 'remote-inbound-rtp', 'transport']) # clean shutdown run(sender.stop())
def test_track_ended(self): track = AudioStreamTrack() sender = RTCRtpSender(track, self.local_transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) # stop track and wait for RTP loop to exit track.stop() run(asyncio.sleep(0.1))
def test_stop_on_exception(self): sender = RTCRtpSender(BuggyStreamTrack(), self.local_transport) self.assertEqual(sender.kind, "audio") run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) # clean shutdown run(sender.stop())
def test_stop(self): sender = RTCRtpSender(AudioStreamTrack(), self.local_transport) self.assertEqual(sender.kind, 'audio') run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) # clean shutdown run(sender.stop())
async def test_stop_on_exception(self): async with dummy_dtls_transport_pair() as (local_transport, _): sender = RTCRtpSender(BuggyStreamTrack(), local_transport) self.assertEqual(sender.kind, "audio") await sender.send(RTCRtpParameters(codecs=[PCMU_CODEC])) # clean shutdown await sender.stop()
async def test_log_debug(self, mock_is_enabled_for): mock_is_enabled_for.return_value = True async with dummy_dtls_transport_pair() as (local_transport, _): sender = RTCRtpSender(VideoStreamTrack(), local_transport) await sender.send(RTCRtpParameters(codecs=[VP8_CODEC])) # clean shutdown await sender.stop()
async def test_track_ended(self): async with dummy_dtls_transport_pair() as (local_transport, _): track = AudioStreamTrack() sender = RTCRtpSender(track, local_transport) await sender.send(RTCRtpParameters(codecs=[PCMU_CODEC])) # stop track and wait for RTP loop to exit track.stop() await asyncio.sleep(0.1)
def test_connection_error(self): """ Close the underlying transport before the sender. """ sender = RTCRtpSender(AudioStreamTrack(), self.local_transport) self.assertEqual(sender.kind, 'audio') run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) run(self.local_transport.stop())
def test_track_ended(self): transport, _ = dummy_dtls_transport_pair() track = AudioStreamTrack() sender = RTCRtpSender(track, transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) track.stop() run(asyncio.sleep(0.5)) run(transport.stop())
async def test_connection_error(self): """ Close the underlying transport before the sender. """ async with dummy_dtls_transport_pair() as (local_transport, _): sender = RTCRtpSender(AudioStreamTrack(), local_transport) self.assertEqual(sender.kind, "audio") await sender.send(RTCRtpParameters(codecs=[PCMU_CODEC])) await local_transport.stop()
def test_stop(self): transport, _ = dummy_dtls_transport_pair() sender = RTCRtpSender(AudioStreamTrack(), transport) self.assertEqual(sender.kind, 'audio') self.assertEqual(sender.transport, transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) # clean shutdown run(sender.stop())
def test_handle_rtcp_pli(self): sender = RTCRtpSender(VideoStreamTrack(), self.local_transport) self.assertEqual(sender.kind, "video") run(sender.send(RTCRtpParameters(codecs=[VP8_CODEC]))) # receive RTCP feedback NACK packet = RtcpPsfbPacket(fmt=RTCP_PSFB_PLI, ssrc=1234, media_ssrc=sender._ssrc) run(sender._handle_rtcp_packet(packet)) # clean shutdown run(sender.stop())
def test_connection_error(self): """ Close the underlying transport before the receiver. """ transport, _ = dummy_dtls_transport_pair() receiver = RTCRtpReceiver('audio', transport) self.assertEqual(receiver.transport, transport) run(receiver.receive(RTCRtpParameters(codecs=[PCMU_CODEC]))) run(transport.close())