Example #1
0
    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))
Example #2
0
    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_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())
Example #4
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()
Example #5
0
    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())
Example #6
0
    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())
Example #8
0
    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())
Example #9
0
    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())
Example #10
0
    def test_connection_error(self):
        """
        Close the underlying transport before the sender.
        """
        transport, _ = dummy_dtls_transport_pair()

        sender = RTCRtpSender(AudioStreamTrack(), transport)
        self.assertEqual(sender.kind, 'audio')
        self.assertEqual(sender.transport, transport)

        run(asyncio.gather(sender._run(codec=PCMU_CODEC), transport.close()))
Example #11
0
    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())
Example #12
0
    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())
Example #13
0
    def test_connection_error(self):
        """
        Close the underlying transport before the sender.
        """
        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])))

        run(transport.stop())
Example #14
0
    def test_capabilities(self):
        # audio
        capabilities = RTCRtpSender.getCapabilities('audio')
        self.assertTrue(isinstance(capabilities, RTCRtpCapabilities))
        self.assertEqual(capabilities.codecs, [
            RTCRtpCodecCapability(
                mimeType='audio/opus', clockRate=48000, channels=2),
            RTCRtpCodecCapability(
                mimeType='audio/PCMU', clockRate=8000, channels=1),
            RTCRtpCodecCapability(
                mimeType='audio/PCMA', clockRate=8000, channels=1),
        ])
        self.assertEqual(capabilities.headerExtensions, [
            RTCRtpHeaderExtensionCapability(
                uri='urn:ietf:params:rtp-hdrext:sdes:mid'),
        ])

        # video
        capabilities = RTCRtpSender.getCapabilities('video')
        self.assertTrue(isinstance(capabilities, RTCRtpCapabilities))
        self.assertEqual(capabilities.codecs, [
            RTCRtpCodecCapability(mimeType='video/VP8', clockRate=90000),
            RTCRtpCodecCapability(mimeType='video/rtx', clockRate=90000),
            RTCRtpCodecCapability(mimeType='video/H264',
                                  clockRate=90000,
                                  parameters=OrderedDict(
                                      [('packetization-mode', '1'),
                                       ('level-asymmetry-allowed', '1'),
                                       ('profile-level-id', '42001f')])),
            RTCRtpCodecCapability(mimeType='video/H264',
                                  clockRate=90000,
                                  parameters=OrderedDict(
                                      [('packetization-mode', '1'),
                                       ('level-asymmetry-allowed', '1'),
                                       ('profile-level-id', '42e01f')])),
        ])
        self.assertEqual(
            capabilities.headerExtensions,
            [
                RTCRtpHeaderExtensionCapability(
                    uri='urn:ietf:params:rtp-hdrext:sdes:mid'),
                RTCRtpHeaderExtensionCapability(
                    uri=
                    'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time'
                ),  # noqa
            ])

        # bogus
        capabilities = RTCRtpSender.getCapabilities('bogus')
        self.assertIsNone(capabilities)
Example #15
0
    async def test_retransmit_with_rtx(self):
        """
        Ask for an RTP packet retransmission.
        """
        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)
            sender._ssrc = 1234
            sender._rtx_ssrc = 2345
            self.assertEqual(sender.kind, "video")

            await sender.send(
                RTCRtpParameters(codecs=[
                    VP8_CODEC,
                    RTCRtpCodecParameters(
                        mimeType="video/rtx",
                        clockRate=90000,
                        payloadType=101,
                        parameters={"apt": 100},
                    ),
                ]))

            # wait for one packet to be transmitted, and ask to retransmit
            packet = await queue.get()
            await sender._retransmit(packet.sequence_number)

            # wait for packet to be retransmitted, then shutdown
            await asyncio.sleep(0.1)
            await sender.stop()

            # check packet was retransmitted
            found_rtx = None
            while not queue.empty():
                queue_packet = queue.get_nowait()
                if queue_packet.payload_type == 101:
                    found_rtx = queue_packet
                    break
            self.assertIsNotNone(found_rtx)
            self.assertEqual(found_rtx.payload_type, 101)
            self.assertEqual(found_rtx.ssrc, 2345)
            self.assertEqual(found_rtx.payload[0:2],
                             pack("!H", packet.sequence_number))
Example #16
0
    def test_handle_rtcp_nack(self):
        sender = RTCRtpSender(VideoStreamTrack(), self.local_transport)
        self.assertEqual(sender.kind, 'video')

        run(sender.send(RTCRtpParameters(codecs=[VP8_CODEC])))

        # receive RTCP feedback NACK
        packet = RtcpRtpfbPacket(fmt=RTCP_RTPFB_NACK,
                                 ssrc=1234,
                                 media_ssrc=sender._ssrc)
        packet.lost.append(7654)
        run(sender._handle_rtcp_packet(packet))

        # clean shutdown
        run(sender.stop())
Example #17
0
    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()
Example #18
0
    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()
Example #19
0
    async def __offer(self, request):
        """
        Generates JSON Response with a WebRTC Peer Connection of Video Server.
        """
        # get offer from params
        params = await request.json()
        offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"])

        # initiate stream
        if not (self.__default_rtc_server is
                None) and not (self.__default_rtc_server.is_launched):
            if self.__logging:
                logger.debug("Initiating Video Streaming.")
            self.__default_rtc_server.launch()

        # setup RTC peer connection - interface represents a WebRTC connection
        # between the local computer and a remote peer.
        pc = RTCPeerConnection()
        self.__pcs.add(pc)
        if self.__logging:
            logger.info("Created WebRTC Peer Connection.")

        # track ICE connection state changes
        @pc.on("iceconnectionstatechange")
        async def on_iceconnectionstatechange():
            logger.debug("ICE connection state is %s" % pc.iceConnectionState)
            if pc.iceConnectionState == "failed":
                logger.error("ICE connection state failed.")
                # check if Live Broadcasting is enabled
                if self.__relay is None:
                    # if not, close connection.
                    await pc.close()
                    self.__pcs.discard(pc)

        # Change the remote description associated with the connection.
        await pc.setRemoteDescription(offer)
        # retrieve list of RTCRtpTransceiver objects that are currently attached to the connection
        for t in pc.getTransceivers():
            # Increments performance significantly, IDK why this works as H265 codec is not even supported :D
            capabilities = RTCRtpSender.getCapabilities("video")
            preferences = list(
                filter(lambda x: x.name == "H265", capabilities.codecs))
            t.setCodecPreferences(preferences)
            # add video server to peer track
            if t.kind == "video":
                pc.addTrack(
                    self.__relay.subscribe(self.config["server"]) if not (
                        self.__relay is None) else self.config["server"])

        # Create an SDP answer to an offer received from a remote peer
        answer = await pc.createAnswer()

        # Change the local description for the answer
        await pc.setLocalDescription(answer)

        # return Starlette json response
        return JSONResponse({
            "sdp": pc.localDescription.sdp,
            "type": pc.localDescription.type
        })
Example #20
0
    def test_handle_rtcp_pli(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 NACK
        packet = RtcpPsfbPacket(fmt=RTCP_PSFB_PLI, ssrc=1234, media_ssrc=5678)
        run(sender._handle_rtcp_packet(packet))

        # clean shutdown
        run(sender.stop())
Example #21
0
    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()
Example #22
0
    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()
Example #23
0
    def test_handle_rtcp_nack(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 feedback NACK
        packet = RtcpRtpfbPacket(fmt=RTCP_RTPFB_NACK, ssrc=1234, media_ssrc=5678)
        packet.lost.append(7654)
        run(sender._handle_rtcp_packet(packet))

        # clean shutdown
        run(sender.stop())
Example #24
0
    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)
Example #25
0
    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()
Example #26
0
    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())
Example #27
0
    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())
Example #28
0
    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())
Example #29
0
    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())
Example #30
0
    def test_retransmit(self):
        """
        Ask for an RTP packet retransmission.
        """
        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 to retransmit
        packet = run(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 queue.empty():
            queue_packet = queue.get_nowait()
            if queue_packet.sequence_number == packet.sequence_number:
                found_rtx = True
        self.assertTrue(found_rtx)